cc-codeconductor 0.2.10 → 0.3.1

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 (63) hide show
  1. package/README.md +5 -4
  2. package/dist/index.js +1636 -1078
  3. package/package.json +1 -1
  4. package/presets/agy/AGENTS.md +46 -2
  5. package/presets/claude/CLAUDE.md +62 -2
  6. package/presets/claude/skills/android/SKILL.md +119 -0
  7. package/presets/claude/skills/laravel-specialist/SKILL.md +264 -0
  8. package/presets/claude/skills/laravel-specialist/references/eloquent.md +351 -0
  9. package/presets/claude/skills/laravel-specialist/references/livewire.md +512 -0
  10. package/presets/claude/skills/laravel-specialist/references/queues.md +423 -0
  11. package/presets/claude/skills/laravel-specialist/references/routing.md +362 -0
  12. package/presets/claude/skills/laravel-specialist/references/testing.md +522 -0
  13. package/presets/claude/skills/php-pro/SKILL.md +208 -0
  14. package/presets/claude/skills/php-pro/references/async-patterns.md +412 -0
  15. package/presets/claude/skills/php-pro/references/laravel-patterns.md +377 -0
  16. package/presets/claude/skills/php-pro/references/modern-php-features.md +323 -0
  17. package/presets/claude/skills/php-pro/references/symfony-patterns.md +466 -0
  18. package/presets/claude/skills/php-pro/references/testing-quality.md +466 -0
  19. package/presets/codex/AGENTS.md +47 -2
  20. package/presets/codex/skills/android/SKILL.md +119 -0
  21. package/presets/codex/skills/laravel-specialist/SKILL.md +264 -0
  22. package/presets/codex/skills/laravel-specialist/references/eloquent.md +351 -0
  23. package/presets/codex/skills/laravel-specialist/references/livewire.md +512 -0
  24. package/presets/codex/skills/laravel-specialist/references/queues.md +423 -0
  25. package/presets/codex/skills/laravel-specialist/references/routing.md +362 -0
  26. package/presets/codex/skills/laravel-specialist/references/testing.md +522 -0
  27. package/presets/codex/skills/php-pro/SKILL.md +208 -0
  28. package/presets/codex/skills/php-pro/references/async-patterns.md +412 -0
  29. package/presets/codex/skills/php-pro/references/laravel-patterns.md +377 -0
  30. package/presets/codex/skills/php-pro/references/modern-php-features.md +323 -0
  31. package/presets/codex/skills/php-pro/references/symfony-patterns.md +466 -0
  32. package/presets/codex/skills/php-pro/references/testing-quality.md +466 -0
  33. package/presets/opencode/agents/implementer.md +2 -2
  34. package/presets/opencode/agents/orchestrator.md +132 -5
  35. package/presets/opencode/agents/reviewer.md +33 -0
  36. package/presets/opencode/prompts/v0.3.0/architect.md +221 -0
  37. package/presets/opencode/prompts/v0.3.0/docs.md +189 -0
  38. package/presets/opencode/prompts/v0.3.0/implementer.md +162 -0
  39. package/presets/opencode/prompts/v0.3.0/orchestrator.md +360 -0
  40. package/presets/opencode/prompts/v0.3.0/repo-explorer.md +110 -0
  41. package/presets/opencode/prompts/v0.3.0/reviewer.md +225 -0
  42. package/presets/opencode/prompts/v0.3.0/task-coach.md +155 -0
  43. package/presets/opencode/prompts/v0.3.0/tester.md +251 -0
  44. package/presets/opencode/skills/android/SKILL.md +119 -0
  45. package/presets/opencode/skills/laravel-specialist/SKILL.md +264 -0
  46. package/presets/opencode/skills/laravel-specialist/references/eloquent.md +351 -0
  47. package/presets/opencode/skills/laravel-specialist/references/livewire.md +512 -0
  48. package/presets/opencode/skills/laravel-specialist/references/queues.md +423 -0
  49. package/presets/opencode/skills/laravel-specialist/references/routing.md +362 -0
  50. package/presets/opencode/skills/laravel-specialist/references/testing.md +522 -0
  51. package/presets/opencode/skills/php-pro/SKILL.md +208 -0
  52. package/presets/opencode/skills/php-pro/references/async-patterns.md +412 -0
  53. package/presets/opencode/skills/php-pro/references/laravel-patterns.md +377 -0
  54. package/presets/opencode/skills/php-pro/references/modern-php-features.md +323 -0
  55. package/presets/opencode/skills/php-pro/references/symfony-patterns.md +466 -0
  56. package/presets/opencode/skills/php-pro/references/testing-quality.md +466 -0
  57. package/src/presets/manifests/agy.yml +3 -2
  58. package/src/presets/manifests/claude.yml +3 -2
  59. package/src/presets/manifests/codex.yml +3 -2
  60. package/src/presets/manifests/cursor.yml +3 -2
  61. package/src/presets/manifests/gemini.yml +3 -2
  62. package/src/presets/manifests/opencode.yml +3 -2
  63. package/src/presets/models/opencode.yml +6 -6
@@ -0,0 +1,522 @@
1
+ # Testing
2
+
3
+ ## Feature Tests
4
+
5
+ ```php
6
+ namespace Tests\Feature;
7
+
8
+ use Tests\TestCase;
9
+ use App\Models\{User, Post};
10
+ use Illuminate\Foundation\Testing\RefreshDatabase;
11
+
12
+ class PostTest extends TestCase
13
+ {
14
+ use RefreshDatabase;
15
+
16
+ public function test_user_can_create_post(): void
17
+ {
18
+ $user = User::factory()->create();
19
+
20
+ $response = $this->actingAs($user)->post('/api/posts', [
21
+ 'title' => 'Test Post',
22
+ 'content' => 'This is a test post content.',
23
+ ]);
24
+
25
+ $response->assertStatus(201)
26
+ ->assertJson([
27
+ 'data' => [
28
+ 'title' => 'Test Post',
29
+ ],
30
+ ]);
31
+
32
+ $this->assertDatabaseHas('posts', [
33
+ 'title' => 'Test Post',
34
+ 'user_id' => $user->id,
35
+ ]);
36
+ }
37
+
38
+ public function test_guest_cannot_create_post(): void
39
+ {
40
+ $response = $this->post('/api/posts', [
41
+ 'title' => 'Test Post',
42
+ 'content' => 'Content',
43
+ ]);
44
+
45
+ $response->assertStatus(401);
46
+ }
47
+
48
+ public function test_post_requires_valid_data(): void
49
+ {
50
+ $user = User::factory()->create();
51
+
52
+ $response = $this->actingAs($user)->post('/api/posts', [
53
+ 'title' => 'AB', // Too short
54
+ ]);
55
+
56
+ $response->assertStatus(422)
57
+ ->assertJsonValidationErrors(['title', 'content']);
58
+ }
59
+
60
+ public function test_user_can_view_their_posts(): void
61
+ {
62
+ $user = User::factory()->create();
63
+ $posts = Post::factory()->count(3)->create(['user_id' => $user->id]);
64
+
65
+ $response = $this->actingAs($user)->get('/api/posts');
66
+
67
+ $response->assertStatus(200)
68
+ ->assertJsonCount(3, 'data')
69
+ ->assertJsonStructure([
70
+ 'data' => [
71
+ '*' => ['id', 'title', 'content', 'created_at'],
72
+ ],
73
+ ]);
74
+ }
75
+
76
+ public function test_user_can_update_own_post(): void
77
+ {
78
+ $user = User::factory()->create();
79
+ $post = Post::factory()->create(['user_id' => $user->id]);
80
+
81
+ $response = $this->actingAs($user)->put("/api/posts/{$post->id}", [
82
+ 'title' => 'Updated Title',
83
+ 'content' => $post->content,
84
+ ]);
85
+
86
+ $response->assertStatus(200);
87
+
88
+ $this->assertDatabaseHas('posts', [
89
+ 'id' => $post->id,
90
+ 'title' => 'Updated Title',
91
+ ]);
92
+ }
93
+
94
+ public function test_user_cannot_update_others_post(): void
95
+ {
96
+ $user = User::factory()->create();
97
+ $otherUser = User::factory()->create();
98
+ $post = Post::factory()->create(['user_id' => $otherUser->id]);
99
+
100
+ $response = $this->actingAs($user)->put("/api/posts/{$post->id}", [
101
+ 'title' => 'Updated Title',
102
+ ]);
103
+
104
+ $response->assertStatus(403);
105
+ }
106
+ }
107
+ ```
108
+
109
+ ## Unit Tests
110
+
111
+ ```php
112
+ namespace Tests\Unit;
113
+
114
+ use Tests\TestCase;
115
+ use App\Models\Post;
116
+ use App\Services\PostService;
117
+ use Illuminate\Foundation\Testing\RefreshDatabase;
118
+
119
+ class PostServiceTest extends TestCase
120
+ {
121
+ use RefreshDatabase;
122
+
123
+ public function test_generates_unique_slug(): void
124
+ {
125
+ $service = new PostService();
126
+
127
+ $slug = $service->generateSlug('Test Post');
128
+
129
+ $this->assertEquals('test-post', $slug);
130
+ }
131
+
132
+ public function test_increments_slug_on_duplicate(): void
133
+ {
134
+ Post::factory()->create(['slug' => 'test-post']);
135
+
136
+ $service = new PostService();
137
+ $slug = $service->generateSlug('Test Post');
138
+
139
+ $this->assertEquals('test-post-1', $slug);
140
+ }
141
+
142
+ public function test_post_excerpt_returns_limited_content(): void
143
+ {
144
+ $post = new Post(['content' => str_repeat('a', 200)]);
145
+
146
+ $excerpt = $post->excerpt;
147
+
148
+ $this->assertLessThanOrEqual(100, strlen($excerpt));
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Pest PHP
154
+
155
+ ```php
156
+ <?php
157
+
158
+ use App\Models\{User, Post};
159
+
160
+ it('allows authenticated users to create posts', function () {
161
+ $user = User::factory()->create();
162
+
163
+ $this->actingAs($user)
164
+ ->post('/api/posts', [
165
+ 'title' => 'Test Post',
166
+ 'content' => 'Content',
167
+ ])
168
+ ->assertStatus(201);
169
+
170
+ expect(Post::count())->toBe(1);
171
+ });
172
+
173
+ it('prevents guests from creating posts', function () {
174
+ $this->post('/api/posts', [
175
+ 'title' => 'Test Post',
176
+ 'content' => 'Content',
177
+ ])->assertStatus(401);
178
+ });
179
+
180
+ test('post requires title and content', function () {
181
+ $user = User::factory()->create();
182
+
183
+ $this->actingAs($user)
184
+ ->post('/api/posts', [])
185
+ ->assertJsonValidationErrors(['title', 'content']);
186
+ });
187
+
188
+ // Datasets
189
+ it('validates title length', function (string $title, bool $shouldPass) {
190
+ $user = User::factory()->create();
191
+
192
+ $response = $this->actingAs($user)->post('/api/posts', [
193
+ 'title' => $title,
194
+ 'content' => 'Content',
195
+ ]);
196
+
197
+ if ($shouldPass) {
198
+ $response->assertStatus(201);
199
+ } else {
200
+ $response->assertJsonValidationErrors(['title']);
201
+ }
202
+ })->with([
203
+ ['AB', false], // Too short
204
+ ['ABC', true], // Minimum valid
205
+ [str_repeat('A', 255), true], // Maximum valid
206
+ [str_repeat('A', 256), false], // Too long
207
+ ]);
208
+
209
+ // Hooks
210
+ beforeEach(function () {
211
+ $this->user = User::factory()->create();
212
+ });
213
+
214
+ afterEach(function () {
215
+ // Cleanup
216
+ });
217
+ ```
218
+
219
+ ## Factories
220
+
221
+ ```php
222
+ namespace Database\Factories;
223
+
224
+ use App\Models\{User, Category};
225
+ use Illuminate\Database\Eloquent\Factories\Factory;
226
+
227
+ class PostFactory extends Factory
228
+ {
229
+ public function definition(): array
230
+ {
231
+ return [
232
+ 'title' => fake()->sentence(),
233
+ 'slug' => fake()->slug(),
234
+ 'content' => fake()->paragraphs(3, true),
235
+ 'excerpt' => fake()->text(100),
236
+ 'published_at' => fake()->dateTimeBetween('-1 year', 'now'),
237
+ 'user_id' => User::factory(),
238
+ 'category_id' => Category::factory(),
239
+ ];
240
+ }
241
+
242
+ public function unpublished(): static
243
+ {
244
+ return $this->state(fn (array $attributes) => [
245
+ 'published_at' => null,
246
+ ]);
247
+ }
248
+
249
+ public function published(): static
250
+ {
251
+ return $this->state(fn (array $attributes) => [
252
+ 'published_at' => now(),
253
+ ]);
254
+ }
255
+
256
+ public function forUser(User $user): static
257
+ {
258
+ return $this->state(fn (array $attributes) => [
259
+ 'user_id' => $user->id,
260
+ ]);
261
+ }
262
+
263
+ public function configure(): static
264
+ {
265
+ return $this->afterCreating(function (Post $post) {
266
+ $post->tags()->attach(
267
+ Tag::factory()->count(3)->create()
268
+ );
269
+ });
270
+ }
271
+ }
272
+
273
+ // Usage
274
+ $post = Post::factory()->create();
275
+ $unpublished = Post::factory()->unpublished()->create();
276
+ $posts = Post::factory()->count(10)->create();
277
+ $userPosts = Post::factory()->forUser($user)->count(5)->create();
278
+
279
+ // With relationships
280
+ $post = Post::factory()
281
+ ->has(Comment::factory()->count(3))
282
+ ->create();
283
+
284
+ // For relationship
285
+ $posts = Post::factory()
286
+ ->count(3)
287
+ ->for($user)
288
+ ->create();
289
+ ```
290
+
291
+ ## Mocking
292
+
293
+ ```php
294
+ use App\Services\ExternalApiService;
295
+ use Illuminate\Support\Facades\Http;
296
+
297
+ public function test_fetches_data_from_external_api(): void
298
+ {
299
+ Http::fake([
300
+ 'api.example.com/*' => Http::response([
301
+ 'data' => ['id' => 1, 'name' => 'Test'],
302
+ ], 200),
303
+ ]);
304
+
305
+ $service = new ExternalApiService();
306
+ $result = $service->fetchData();
307
+
308
+ $this->assertEquals('Test', $result['name']);
309
+
310
+ Http::assertSent(function ($request) {
311
+ return $request->url() === 'https://api.example.com/data' &&
312
+ $request->hasHeader('Authorization');
313
+ });
314
+ }
315
+
316
+ // Mock events
317
+ use Illuminate\Support\Facades\Event;
318
+
319
+ Event::fake([PostCreated::class]);
320
+
321
+ // Test code that dispatches events
322
+
323
+ Event::assertDispatched(PostCreated::class, function ($event) {
324
+ return $event->post->id === 1;
325
+ });
326
+
327
+ // Mock queues
328
+ use Illuminate\Support\Facades\Queue;
329
+
330
+ Queue::fake();
331
+
332
+ // Test code that dispatches jobs
333
+
334
+ Queue::assertPushed(ProcessPost::class);
335
+ Queue::assertPushed(ProcessPost::class, 2);
336
+ Queue::assertPushed(ProcessPost::class, function ($job) {
337
+ return $job->post->id === 1;
338
+ });
339
+
340
+ // Mock notifications
341
+ use Illuminate\Support\Facades\Notification;
342
+
343
+ Notification::fake();
344
+
345
+ // Test code that sends notifications
346
+
347
+ Notification::assertSentTo($user, PostPublished::class);
348
+
349
+ // Mock storage
350
+ use Illuminate\Support\Facades\Storage;
351
+
352
+ Storage::fake('public');
353
+
354
+ // Test file upload
355
+
356
+ Storage::disk('public')->assertExists('file.jpg');
357
+ Storage::disk('public')->assertMissing('missing.jpg');
358
+ ```
359
+
360
+ ## Database Testing
361
+
362
+ ```php
363
+ use Illuminate\Foundation\Testing\RefreshDatabase;
364
+ use Illuminate\Foundation\Testing\DatabaseTransactions;
365
+
366
+ class PostTest extends TestCase
367
+ {
368
+ use RefreshDatabase; // Migrate database before each test
369
+
370
+ // Or use transactions
371
+ use DatabaseTransactions; // Rollback after each test
372
+
373
+ public function test_database_assertions(): void
374
+ {
375
+ $post = Post::factory()->create([
376
+ 'title' => 'Test Post',
377
+ ]);
378
+
379
+ $this->assertDatabaseHas('posts', [
380
+ 'title' => 'Test Post',
381
+ ]);
382
+
383
+ $post->delete();
384
+
385
+ $this->assertDatabaseMissing('posts', [
386
+ 'id' => $post->id,
387
+ ]);
388
+
389
+ $this->assertSoftDeleted('posts', [
390
+ 'id' => $post->id,
391
+ ]);
392
+ }
393
+
394
+ public function test_model_exists(): void
395
+ {
396
+ $post = Post::factory()->create();
397
+
398
+ $this->assertModelExists($post);
399
+
400
+ $post->delete();
401
+
402
+ $this->assertModelMissing($post);
403
+ }
404
+ }
405
+ ```
406
+
407
+ ## API Testing
408
+
409
+ ```php
410
+ public function test_api_returns_paginated_posts(): void
411
+ {
412
+ Post::factory()->count(30)->create();
413
+
414
+ $response = $this->get('/api/posts');
415
+
416
+ $response->assertStatus(200)
417
+ ->assertJsonStructure([
418
+ 'data' => [
419
+ '*' => ['id', 'title', 'content'],
420
+ ],
421
+ 'meta' => ['total', 'current_page', 'last_page'],
422
+ 'links' => ['first', 'last', 'prev', 'next'],
423
+ ])
424
+ ->assertJsonCount(15, 'data'); // Default per page
425
+ }
426
+
427
+ public function test_api_filters_posts_by_category(): void
428
+ {
429
+ $category = Category::factory()->create();
430
+ Post::factory()->count(5)->create(['category_id' => $category->id]);
431
+ Post::factory()->count(5)->create();
432
+
433
+ $response = $this->get("/api/posts?category={$category->id}");
434
+
435
+ $response->assertJsonCount(5, 'data')
436
+ ->assertJson([
437
+ 'data' => [
438
+ ['category_id' => $category->id],
439
+ ],
440
+ ]);
441
+ }
442
+ ```
443
+
444
+ ## Authentication Testing
445
+
446
+ ```php
447
+ use Laravel\Sanctum\Sanctum;
448
+
449
+ public function test_authenticated_user_can_access_endpoint(): void
450
+ {
451
+ $user = User::factory()->create();
452
+
453
+ Sanctum::actingAs($user, ['*']);
454
+
455
+ $response = $this->get('/api/user');
456
+
457
+ $response->assertStatus(200)
458
+ ->assertJson([
459
+ 'data' => [
460
+ 'id' => $user->id,
461
+ 'email' => $user->email,
462
+ ],
463
+ ]);
464
+ }
465
+
466
+ public function test_user_with_wrong_ability_cannot_access(): void
467
+ {
468
+ $user = User::factory()->create();
469
+
470
+ Sanctum::actingAs($user, ['view-posts']);
471
+
472
+ $response = $this->post('/api/posts', [
473
+ 'title' => 'Test',
474
+ 'content' => 'Content',
475
+ ]);
476
+
477
+ $response->assertStatus(403);
478
+ }
479
+ ```
480
+
481
+ ## Running Tests
482
+
483
+ ```bash
484
+ # Run all tests
485
+ php artisan test
486
+
487
+ # Run specific test
488
+ php artisan test --filter=test_user_can_create_post
489
+
490
+ # Run test file
491
+ php artisan test tests/Feature/PostTest.php
492
+
493
+ # Parallel testing
494
+ php artisan test --parallel
495
+
496
+ # With coverage
497
+ php artisan test --coverage
498
+
499
+ # Coverage minimum
500
+ php artisan test --coverage --min=80
501
+
502
+ # Stop on failure
503
+ php artisan test --stop-on-failure
504
+
505
+ # Pest specific
506
+ ./vendor/bin/pest
507
+ ./vendor/bin/pest --filter=PostTest
508
+ ./vendor/bin/pest --coverage
509
+ ```
510
+
511
+ ## Best Practices
512
+
513
+ 1. **Use RefreshDatabase** - Clean database for each test
514
+ 2. **Use factories** - Don't manually create test data
515
+ 3. **Test one thing** - Each test should verify one behavior
516
+ 4. **Use descriptive names** - test_user_can_create_post
517
+ 5. **AAA pattern** - Arrange, Act, Assert
518
+ 6. **Mock external services** - Don't make real API calls
519
+ 7. **Fake queues and events** - Test async code synchronously
520
+ 8. **Test edge cases** - Invalid data, permissions, etc.
521
+ 9. **Achieve >85% coverage** - Test critical paths
522
+ 10. **Run tests in CI/CD** - Automate test execution