@vibe-agent-toolkit/vat-development-agents 0.1.29 → 0.1.30-rc.2

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 (33) hide show
  1. package/dist/.claude/plugins/marketplaces/vat-skills/CHANGELOG.md +20 -0
  2. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/.claude-plugin/plugin.json +1 -1
  3. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/audit/SKILL.md +21 -16
  4. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/authoring/SKILL.md +30 -12
  5. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/authoring/resources/skill-quality-checklist.md +42 -0
  6. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/debugging/SKILL.md +4 -4
  7. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/SKILL.md +6 -6
  8. package/dist/generated/resources/skills/vat-agent-authoring.js +3 -3
  9. package/dist/generated/resources/skills/vat-audit.js +5 -5
  10. package/dist/skills/audit/SKILL.md +21 -16
  11. package/dist/skills/authoring/SKILL.md +30 -12
  12. package/dist/skills/authoring/resources/skill-quality-checklist.md +42 -0
  13. package/dist/skills/debugging/SKILL.md +4 -4
  14. package/dist/skills/vibe-agent-toolkit/SKILL.md +6 -6
  15. package/package.json +4 -4
  16. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/debugging/resources/CLAUDE.md +0 -539
  17. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/debugging/resources/debug-and-test-vat-fixes.md +0 -111
  18. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/debugging/resources/writing-tests.md +0 -577
  19. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/adding-runtime-adapters.md +0 -628
  20. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/agent-authoring.md +0 -905
  21. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/compiling-markdown-to-typescript.md +0 -501
  22. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/getting-started.md +0 -360
  23. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/orchestration.md +0 -859
  24. package/dist/.claude/plugins/marketplaces/vat-skills/plugins/vibe-agent-toolkit/skills/vibe-agent-toolkit/resources/rag-usage-guide.md +0 -770
  25. package/dist/skills/debugging/resources/CLAUDE.md +0 -539
  26. package/dist/skills/debugging/resources/debug-and-test-vat-fixes.md +0 -111
  27. package/dist/skills/debugging/resources/writing-tests.md +0 -577
  28. package/dist/skills/vibe-agent-toolkit/resources/adding-runtime-adapters.md +0 -628
  29. package/dist/skills/vibe-agent-toolkit/resources/agent-authoring.md +0 -905
  30. package/dist/skills/vibe-agent-toolkit/resources/compiling-markdown-to-typescript.md +0 -501
  31. package/dist/skills/vibe-agent-toolkit/resources/getting-started.md +0 -360
  32. package/dist/skills/vibe-agent-toolkit/resources/orchestration.md +0 -859
  33. package/dist/skills/vibe-agent-toolkit/resources/rag-usage-guide.md +0 -770
@@ -1,577 +0,0 @@
1
- # Writing Tests Guide
2
-
3
- **CRITICAL**: Code duplication in tests will block commits and PR merges. Follow these patterns to avoid duplication from the start.
4
-
5
- ## Quick Reference
6
-
7
- **When writing ANY new test file:**
8
- 1. Create `test/test-helpers.ts` if it doesn't exist
9
- 2. After writing 2-3 similar tests, extract a `setupXTestSuite()` helper
10
- 3. Use `toForwardSlash()` from `@vibe-agent-toolkit/utils` for cross-platform path comparisons
11
- 4. Run `bun run duplication-check` before committing
12
-
13
- ## Test File Organization
14
-
15
- ### Directory Structure
16
-
17
- ```
18
- packages/my-package/
19
- ├── src/
20
- │ └── my-module.ts # Source code
21
- ├── test/
22
- │ ├── test-helpers.ts # Shared test utilities
23
- │ ├── my-module.test.ts # Unit tests
24
- │ ├── integration/
25
- │ │ └── workflow.integration.test.ts
26
- │ └── system/
27
- │ └── e2e.system.test.ts
28
- └── package.json
29
- ```
30
-
31
- ### Test Types
32
-
33
- | Type | Location | Purpose | Speed | Dependencies |
34
- |------|----------|---------|-------|--------------|
35
- | **Unit** | `test/*.test.ts` | Test functions/classes in isolation | < 100ms | Mock external deps |
36
- | **Integration** | `test/integration/*.integration.test.ts` | Test multiple modules together | < 5s | Real file system, DBs |
37
- | **System** | `test/system/*.system.test.ts` | End-to-end workflows | < 30s | Real external services |
38
-
39
- ### Test Classification Rules
40
-
41
- Misclassified tests are the #1 cause of flaky CI and slow unit test suites. If your test does any of the following, it is **NOT a unit test**:
42
-
43
- | If your test... | It belongs in... | Why |
44
- |----------------|-----------------|-----|
45
- | Makes real HTTP requests | **Integration** | Network flakiness breaks CI; 2-15s per request |
46
- | Loads ML models (Transformers.js, ONNX) | **Integration** | Model loading costs 2-5s; native bindings crash threads pool |
47
- | Spawns child processes (`spawnSync`, `exec`) | **System** | Node startup overhead ~1-2s per spawn |
48
- | Connects to a real database | **Integration** | Requires external service |
49
- | Reads/writes real files (not mocked) | **Integration** | I/O-dependent, slower |
50
-
51
- **Unit tests must be deterministic, fast, and isolated.** Mock all I/O, network, and heavy dependencies. If you're unsure, ask: "Would this test fail on an airplane?" If yes, it's not a unit test.
52
-
53
- **Network-dependent integration tests** should use `describe.skipIf(!!process.env.CI)` if they hit external services that may be unreachable in CI:
54
-
55
- ```typescript
56
- // Tests that make real HTTP requests — skip in CI where egress may be restricted
57
- describe.skipIf(!!process.env.CI)('ExternalLinkValidator (integration)', () => {
58
- // ...
59
- });
60
- ```
61
-
62
- ## Vitest Pool Compatibility
63
-
64
- Unit tests run with **threads pool on Mac/Unix** (shared module cache, ~20% faster) and **forks pool on Windows** (required for native module isolation). This affects what you can do in tests.
65
-
66
- ### `process.chdir()` — Forbidden in unit tests
67
-
68
- `process.chdir()` throws in worker threads (all workers share one process). Use `vi.spyOn(process, 'cwd')` instead:
69
-
70
- ```typescript
71
- // ❌ WRONG — throws in threads pool (Mac/Unix unit tests)
72
- beforeEach(() => {
73
- originalCwd = process.cwd();
74
- process.chdir(tempDir);
75
- });
76
- afterEach(() => {
77
- process.chdir(originalCwd);
78
- });
79
-
80
- // ✅ CORRECT — works in both threads and forks
81
- beforeEach(() => {
82
- vi.spyOn(process, 'cwd').mockReturnValue(tempDir);
83
- });
84
- afterEach(() => {
85
- vi.restoreAllMocks();
86
- });
87
- ```
88
-
89
- **Caveat**: `vi.spyOn(process, 'cwd')` only affects code that calls `process.cwd()`. It does NOT affect `fs.existsSync('relative/path')` — Node's `fs` module resolves relative paths against the real OS-level CWD, not the mocked one. If your code under test uses `fs` with relative paths, you need one of:
90
- - Absolute paths in your test setup
91
- - `process.chdir()` in integration tests (forks pool)
92
- - Mocking the `fs` functions
93
-
94
- ### When `process.chdir()` is acceptable
95
-
96
- In **integration** or **system** tests (which use forks pool), `process.chdir()` is safe. If a unit test absolutely requires it, add a comment explaining why and ensure the test restores CWD in `afterEach`.
97
-
98
- ## The Test Suite Helper Pattern
99
-
100
- **CRITICAL**: The #1 source of test duplication is repeated `beforeEach`/`afterEach` setup across describe blocks.
101
-
102
- ### When to Create a Suite Helper
103
-
104
- Create a `setupXTestSuite()` helper when:
105
- - ✅ Starting a new test file (proactive)
106
- - ✅ After writing 2-3 similar describe blocks (reactive)
107
- - ✅ You notice repeated setup/teardown code
108
-
109
- **Don't wait for 10+ duplicates to accumulate!**
110
-
111
- ### Basic Pattern
112
-
113
- **Step 1: Create the helper** (in `test/test-helpers.ts`):
114
-
115
- ```typescript
116
- import { mkdtemp, rm } from 'node:fs/promises';
117
- import { tmpdir } from 'node:os';
118
- import { join } from 'node:path';
119
-
120
- import { MyRegistry } from '../src/my-registry.js';
121
-
122
- /**
123
- * Setup test suite with standard lifecycle hooks
124
- * Eliminates duplication of beforeEach/afterEach setup
125
- */
126
- export function setupMyTestSuite(testPrefix: string): {
127
- tempDir: string;
128
- registry: MyRegistry;
129
- beforeEach: () => Promise<void>;
130
- afterEach: () => Promise<void>;
131
- } {
132
- const suite = {
133
- tempDir: '',
134
- registry: null as unknown as MyRegistry,
135
- beforeEach: async () => {
136
- suite.tempDir = await mkdtemp(join(tmpdir(), testPrefix));
137
- suite.registry = new MyRegistry();
138
- },
139
- afterEach: async () => {
140
- await rm(suite.tempDir, { recursive: true, force: true });
141
- },
142
- };
143
-
144
- return suite;
145
- }
146
- ```
147
-
148
- **Step 2: Use in test files**:
149
-
150
- ```typescript
151
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
152
- import { setupMyTestSuite } from './test-helpers.js';
153
-
154
- const suite = setupMyTestSuite('my-test-');
155
-
156
- describe('MyModule basic usage', () => {
157
- beforeEach(suite.beforeEach);
158
- afterEach(suite.afterEach);
159
-
160
- it('should work', async () => {
161
- // Use suite.tempDir, suite.registry
162
- const result = await doSomething(suite.tempDir);
163
- expect(result).toBeDefined();
164
- });
165
- });
166
-
167
- describe('MyModule advanced usage', () => {
168
- beforeEach(suite.beforeEach);
169
- afterEach(suite.afterEach);
170
-
171
- it('should also work', async () => {
172
- // Same suite, different tests
173
- const result = await doSomethingElse(suite.registry);
174
- expect(result).toBeDefined();
175
- });
176
- });
177
- ```
178
-
179
- ### Real-World Examples
180
-
181
- #### Example 1: Resource Tests
182
-
183
- From `packages/resources/test/test-helpers.ts`:
184
-
185
- ```typescript
186
- export function setupResourceTestSuite(testPrefix: string): {
187
- tempDir: string;
188
- registry: ResourceRegistry;
189
- beforeEach: () => Promise<void>;
190
- afterEach: () => Promise<void>;
191
- } {
192
- const suite = {
193
- tempDir: '',
194
- registry: null as unknown as ResourceRegistry,
195
- beforeEach: async () => {
196
- suite.tempDir = await mkdtemp(join(tmpdir(), testPrefix));
197
- suite.registry = new ResourceRegistry();
198
- },
199
- afterEach: async () => {
200
- await rm(suite.tempDir, { recursive: true, force: true });
201
- },
202
- };
203
-
204
- return suite;
205
- }
206
- ```
207
-
208
- **Impact**: Eliminated 8-10 lines per describe block across 6 describe blocks = ~50 lines removed
209
-
210
- #### Example 2: RAG System Tests
211
-
212
- From `packages/cli/test/system/test-helpers.ts`:
213
-
214
- ```typescript
215
- export function setupRagTestSuite(
216
- testName: string,
217
- binPath: string,
218
- getTestOutputDir: (pkg: string, ...segments: string[]) => string
219
- ): {
220
- tempDir: string;
221
- projectDir: string;
222
- dbPath: string;
223
- beforeAll: () => void;
224
- afterAll: () => void;
225
- } {
226
- const suite = {
227
- tempDir: '',
228
- projectDir: '',
229
- dbPath: '',
230
- beforeAll: () => {
231
- suite.dbPath = getTestOutputDir('cli', 'system', `rag-${testName}-db`);
232
- const result = setupIndexedRagTest(
233
- `vat-rag-${testName}-test-`,
234
- 'test-project',
235
- binPath,
236
- suite.dbPath
237
- );
238
- suite.tempDir = result.tempDir;
239
- suite.projectDir = result.projectDir;
240
- },
241
- afterAll: () => {
242
- fs.rmSync(suite.tempDir, { recursive: true, force: true });
243
- },
244
- };
245
-
246
- return suite;
247
- }
248
- ```
249
-
250
- **Impact**: Eliminated 41-62% duplication across 4 system test files
251
-
252
- ## Other Common Helper Patterns
253
-
254
- ### Factory Functions
255
-
256
- Create test entities with sensible defaults:
257
-
258
- ```typescript
259
- export function createTestResource(overrides?: Partial<Resource>): Resource {
260
- return {
261
- id: 'test-id',
262
- name: 'Test Resource',
263
- path: '/tmp/test.md',
264
- ...overrides,
265
- };
266
- }
267
-
268
- // Usage:
269
- const resource = createTestResource({ name: 'Custom Name' });
270
- ```
271
-
272
- ### Assertion Helpers
273
-
274
- Extract repeated assertion patterns:
275
-
276
- ```typescript
277
- export async function assertValidation(
278
- options: {
279
- link: ResourceLink;
280
- sourceFile: string;
281
- expected: ValidationIssue | null;
282
- },
283
- expectFn: (actual: unknown) => Assertion<unknown>
284
- ): Promise<void> {
285
- const result = await validateLink(options.link, options.sourceFile);
286
-
287
- if (options.expected === null) {
288
- expectFn(result).toBeNull();
289
- } else {
290
- expectFn(result).not.toBeNull();
291
- expectFn(result?.severity).toBe(options.expected.severity);
292
- expectFn(result?.type).toBe(options.expected.type);
293
- }
294
- }
295
- ```
296
-
297
- ### Workflow Helpers
298
-
299
- Combine setup → action → partial assert:
300
-
301
- ```typescript
302
- export async function createAndAddResource(
303
- tempDir: string,
304
- filename: string,
305
- content: string,
306
- registry: ResourceRegistry
307
- ): Promise<ResourceMetadata> {
308
- const filePath = join(tempDir, filename);
309
- await writeFile(filePath, content, 'utf-8');
310
- const resource = await parseMarkdown(filePath);
311
- registry.add(resource);
312
- return resource;
313
- }
314
- ```
315
-
316
- ## Cross-Platform Testing
317
-
318
- ### Path Comparisons
319
-
320
- **CRITICAL**: Path comparisons must work on Windows (`\`) and Unix (`/`).
321
-
322
- **Always use `toForwardSlash()` from utils when comparing paths**:
323
-
324
- ```typescript
325
- // ❌ WRONG - fails on Windows
326
- expect(resource.filePath.includes('/docs/')).toBe(true);
327
-
328
- // ✅ CORRECT - works everywhere
329
- import { toForwardSlash } from '@vibe-agent-toolkit/utils';
330
- expect(toForwardSlash(resource.filePath).includes('/docs/')).toBe(true);
331
- ```
332
-
333
- **Why this works**: Windows accepts both forward slashes and backslashes as path separators.
334
- `toForwardSlash()` normalizes all paths to use forward slashes for consistent string comparisons.
335
-
336
- **Example**:
337
- ```typescript
338
- // Windows path: "docs\\api\\guide.md"
339
- // Unix path: "docs/api/guide.md"
340
- // Both normalize to: "docs/api/guide.md"
341
- import { toForwardSlash } from '@vibe-agent-toolkit/utils';
342
- expect(toForwardSlash(resource.filePath)).toContain('/api/')
343
- ```
344
-
345
- ### Path Construction
346
-
347
- Use `path.join()` for constructing paths, never string concatenation:
348
-
349
- ```typescript
350
- // ❌ WRONG
351
- const filePath = tempDir + '/' + 'test.md';
352
-
353
- // ✅ CORRECT
354
- const filePath = join(tempDir, 'test.md');
355
- ```
356
-
357
- ### Hardcoded Path Constants
358
-
359
- When tests use hardcoded fake paths (not real filesystem paths), always use `path.resolve()` so they include the drive letter on Windows. Functions like `path.resolve()`, `path.dirname()`, and `path.join()` prepend the current drive on Windows — if your constants don't match, lookups and assertions fail.
360
-
361
- ```typescript
362
- // ❌ WRONG — '/project/docs/guide.md' becomes 'D:\project\docs\guide.md' after path.resolve()
363
- const PROJECT_ROOT = '/project';
364
- const GUIDE_PATH = '/project/docs/guide.md';
365
-
366
- // ✅ CORRECT — path.resolve() makes constants platform-appropriate
367
- import { resolve } from 'node:path';
368
- const PROJECT_ROOT = resolve('/project'); // '/project' on Unix, 'D:\project' on Windows
369
- const GUIDE_PATH = resolve('/project/docs/guide.md');
370
- ```
371
-
372
- ### `path.join()` with Two Absolute Paths on Windows
373
-
374
- On POSIX, `path.join('/a/b', '/c/d')` produces `/a/b/c/d` (valid). On Windows, `path.join('C:\\a', 'C:\\b')` produces `C:\\a\\C:\\b` — the colon from the second drive letter creates an **invalid path** that crashes `fs` operations.
375
-
376
- ```typescript
377
- // ❌ DANGEROUS — breaks on Windows when both args are absolute
378
- const targetDir = join(distDir, generatedDir); // C:\dist\C:\gen — invalid!
379
-
380
- // ✅ SAFE — use relative paths or basename for the second argument
381
- const targetDir = join(distDir, 'generated');
382
- ```
383
-
384
- If your function joins two user-supplied paths and both could be absolute, you have a Windows compatibility bug. Either:
385
- 1. Ensure one argument is always relative
386
- 2. Use platform-conditional logic (chdir on Windows, absolute paths on Unix)
387
-
388
- ## When to Extract Helpers
389
-
390
- ### The 2-3 Rule
391
-
392
- Extract helpers after seeing a pattern **2-3 times**, not 10+:
393
-
394
- ```typescript
395
- // ❌ BAD - Wait until 10+ duplicates accumulate
396
- describe('Test 1', () => { /* 10 lines of setup */ });
397
- describe('Test 2', () => { /* 10 lines of setup */ });
398
- describe('Test 3', () => { /* 10 lines of setup */ });
399
- // ... 7 more times
400
- // Finally: "Oh, maybe I should extract this?"
401
-
402
- // ✅ GOOD - Extract early
403
- describe('Test 1', () => { /* 10 lines of setup */ });
404
- describe('Test 2', () => { /* 10 lines of setup */ });
405
- // "I see a pattern" → Extract setupXTestSuite()
406
- describe('Test 3', () => {
407
- beforeEach(suite.beforeEach);
408
- afterEach(suite.afterEach);
409
- });
410
- ```
411
-
412
- ### Questions to Ask
413
-
414
- While writing tests:
415
- - ❓ "Have I written similar setup code before?" → Extract factory function
416
- - ❓ "Am I repeating the same assertions?" → Extract assertion helper
417
- - ❓ "Is this a common workflow?" → Extract workflow helper
418
- - ❓ "Do I have 2+ describe blocks with identical beforeEach/afterEach?" → Extract suite helper
419
-
420
- ## Code Duplication Detection
421
-
422
- ### Running the Check
423
-
424
- ```bash
425
- # Before every commit
426
- bun run duplication-check
427
-
428
- # If it fails
429
- bun run duplication-check # See what's duplicated
430
- # → Refactor to eliminate duplication
431
- # → Re-run until it passes
432
- ```
433
-
434
- ### Policy: Zero Tolerance
435
-
436
- **Code duplication will block your PR.** The CI system runs `duplication-check` and fails if any duplication is detected.
437
-
438
- **When duplication is detected:**
439
- 1. ❌ **Don't** update the baseline
440
- 2. ❌ **Don't** add eslint-disable comments
441
- 3. ✅ **Do** extract helpers to eliminate duplication
442
- 4. ✅ **Do** refactor until the check passes
443
-
444
- **The baseline exists to track progress towards zero, not to accept new duplication.**
445
-
446
- ## Time-Dependent Tests
447
-
448
- Never use real `setTimeout` or `Date.now()` waits in tests. They're flaky on loaded CI machines and waste wall-clock time.
449
-
450
- ```typescript
451
- // ❌ WRONG — flaky on slow CI, wastes 10ms per test
452
- await new Promise(resolve => setTimeout(resolve, 10));
453
- expect(cache.isExpired(key)).toBe(true);
454
-
455
- // ✅ CORRECT — deterministic, instant
456
- vi.useFakeTimers();
457
- cache.set(key, value, { ttl: 100 });
458
- vi.advanceTimersByTime(101);
459
- expect(cache.isExpired(key)).toBe(true);
460
- vi.useRealTimers();
461
- ```
462
-
463
- ## Testing Anti-Patterns
464
-
465
- ### ❌ Don't: Copy-paste test setup
466
-
467
- ```typescript
468
- // BAD - Duplicated in every describe block
469
- describe('Feature A', () => {
470
- let tempDir: string;
471
- let registry: Registry;
472
-
473
- beforeEach(async () => {
474
- tempDir = await mkdtemp(join(tmpdir(), 'test-'));
475
- registry = new Registry();
476
- });
477
-
478
- afterEach(async () => {
479
- await rm(tempDir, { recursive: true });
480
- });
481
- });
482
-
483
- describe('Feature B', () => {
484
- // ... same 10 lines repeated
485
- });
486
- ```
487
-
488
- ### ✅ Do: Extract suite helper
489
-
490
- ```typescript
491
- // GOOD - Shared via helper
492
- const suite = setupTestSuite('my-test-');
493
-
494
- describe('Feature A', () => {
495
- beforeEach(suite.beforeEach);
496
- afterEach(suite.afterEach);
497
- });
498
-
499
- describe('Feature B', () => {
500
- beforeEach(suite.beforeEach);
501
- afterEach(suite.afterEach);
502
- });
503
- ```
504
-
505
- ### ❌ Don't: Inline path operations without normalization
506
-
507
- ```typescript
508
- // BAD - Fails on Windows
509
- expect(resource.filePath.includes('/docs/')).toBe(true);
510
- ```
511
-
512
- ### ✅ Do: Normalize before comparison
513
-
514
- ```typescript
515
- // GOOD - Works everywhere
516
- expect(toForwardSlash(resource.filePath)).toContain('/docs/');
517
- ```
518
-
519
- ### ❌ Don't: Write 10 tests before extracting
520
-
521
- ```typescript
522
- // BAD - Wait until massive duplication accumulates
523
- it('test 1', () => { /* repeated setup */ });
524
- // ... 9 more times with identical setup
525
- // Finally extract helper after SonarQube complains
526
- ```
527
-
528
- ### ✅ Do: Extract after 2-3 similar patterns
529
-
530
- ```typescript
531
- // GOOD - Extract early, prevent accumulation
532
- it('test 1', () => { /* setup */ });
533
- it('test 2', () => { /* same setup */ });
534
- // "I see a pattern" → Extract helper now
535
- it('test 3', () => { /* uses helper */ });
536
- ```
537
-
538
- ## Summary Checklist
539
-
540
- When writing tests:
541
-
542
- **Classification:**
543
- - [ ] Test is in the right tier (no network/ML/process spawning in unit tests)
544
- - [ ] Network-dependent integration tests use `describe.skipIf(!!process.env.CI)` if needed
545
-
546
- **Cross-platform:**
547
- - [ ] Used `toForwardSlash()` from utils for path comparisons
548
- - [ ] Used `path.resolve()` for hardcoded fake path constants
549
- - [ ] No `path.join()` with two absolute paths (breaks on Windows)
550
- - [ ] No `process.chdir()` in unit tests (use `vi.spyOn(process, 'cwd')`)
551
- - [ ] All tests pass on both Windows and Unix systems
552
-
553
- **Patterns:**
554
- - [ ] Created `test/test-helpers.ts` for the package
555
- - [ ] Extracted `setupXTestSuite()` helper after 2-3 similar describe blocks
556
- - [ ] Created factory functions for common test entities
557
- - [ ] Extracted assertion helpers for repeated validation patterns
558
- - [ ] Used `vi.useFakeTimers()` instead of real `setTimeout` for time-dependent tests
559
-
560
- **Quality:**
561
- - [ ] Ran `bun run duplication-check` before committing
562
- - [ ] No code duplication detected
563
-
564
- ## Real-World Impact
565
-
566
- **Before applying these patterns:**
567
- - resources package: 25.6% duplication in tests
568
- - RAG system tests: 41-62% duplication per file
569
- - Frequent Windows CI failures from path issues
570
-
571
- **After applying these patterns:**
572
- - resources package: 0% duplication
573
- - RAG system tests: 0% duplication
574
- - All tests pass on Windows and Ubuntu
575
- - Test files 30-50% shorter and more maintainable
576
-
577
- **The key**: Extract helpers EARLY (after 2-3 patterns), not LATE (after 10+ duplicates).