cc-codeconductor 0.2.9 → 0.3.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.
- package/README.md +105 -25
- package/dist/index.js +662 -291
- package/package.json +1 -1
- package/presets/agy/AGENTS.md +365 -0
- package/presets/agy/README.md +47 -0
- package/presets/agy/hooks.json +30 -0
- package/presets/agy/mcp_config.json +3 -0
- package/presets/agy/rules/commit-style.md +1 -0
- package/presets/agy/rules/graphify.md +14 -0
- package/presets/agy/scripts/post-tool.sh +25 -0
- package/presets/agy/scripts/pre-tool.sh +56 -0
- package/presets/agy/settings.json +8 -0
- package/presets/agy/skills/cc-api-contract/SKILL.md +71 -0
- package/presets/agy/skills/cc-db-migration/SKILL.md +70 -0
- package/presets/agy/skills/cc-feature/SKILL.md +115 -0
- package/presets/agy/skills/cc-fix/SKILL.md +124 -0
- package/presets/agy/skills/cc-pagespeed/SKILL.md +101 -0
- package/presets/agy/skills/cc-refactor/SKILL.md +149 -0
- package/presets/agy/skills/cc-review/SKILL.md +142 -0
- package/presets/agy/skills/cc-tdd-cycle/SKILL.md +226 -0
- package/presets/agy/skills/cc-test-plan/SKILL.md +145 -0
- package/presets/agy/skills/commit/SKILL.md +5 -0
- package/presets/agy/workflows/cc-api-contract.md +71 -0
- package/presets/agy/workflows/cc-db-migration.md +70 -0
- package/presets/agy/workflows/cc-feature.md +115 -0
- package/presets/agy/workflows/cc-fix.md +124 -0
- package/presets/agy/workflows/cc-pagespeed.md +101 -0
- package/presets/agy/workflows/cc-refactor.md +149 -0
- package/presets/agy/workflows/cc-review.md +142 -0
- package/presets/agy/workflows/cc-tdd-cycle.md +226 -0
- package/presets/agy/workflows/cc-test-plan.md +145 -0
- package/presets/agy/workflows/commit.md +1 -0
- package/presets/claude/CLAUDE.md +47 -3
- package/presets/claude/claude.json +6 -0
- package/presets/claude/commands/cc/pagespeed.md +103 -0
- package/presets/claude/settings.json +249 -2
- package/presets/claude/skills/android/SKILL.md +119 -0
- package/presets/claude/skills/conductor-setup/SKILL.md +125 -0
- package/presets/claude/skills/find-skills/SKILL.md +142 -0
- package/presets/claude/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/claude/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/claude/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/claude/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/claude/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/claude/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/claude/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/claude/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/claude/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/claude/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/claude/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/claude/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/claude/skills/pagespeed-insights/reference.md +50 -0
- package/presets/claude/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/claude/skills/php-pro/SKILL.md +208 -0
- package/presets/claude/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/claude/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/claude/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/claude/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/claude/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/claude/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/claude/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/codex/AGENTS.md +38 -14
- package/presets/codex/skills/android/SKILL.md +119 -0
- package/presets/codex/skills/conductor-setup/SKILL.md +125 -0
- package/presets/codex/skills/find-skills/SKILL.md +142 -0
- package/presets/codex/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/codex/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/codex/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/codex/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/codex/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/codex/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/codex/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/codex/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/codex/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/codex/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/codex/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/codex/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/codex/skills/pagespeed-insights/reference.md +50 -0
- package/presets/codex/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/codex/skills/php-pro/SKILL.md +208 -0
- package/presets/codex/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/codex/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/codex/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/codex/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/codex/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/codex/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/codex/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/opencode/README.md +11 -10
- package/presets/opencode/agents/orchestrator.md +121 -1
- package/presets/opencode/agents/reviewer.md +31 -0
- package/presets/opencode/commands/cc-pagespeed.md +100 -0
- package/presets/opencode/prompts/v0.3.0/architect.md +221 -0
- package/presets/opencode/prompts/v0.3.0/docs.md +189 -0
- package/presets/opencode/prompts/v0.3.0/implementer.md +162 -0
- package/presets/opencode/prompts/v0.3.0/orchestrator.md +360 -0
- package/presets/opencode/prompts/v0.3.0/repo-explorer.md +110 -0
- package/presets/opencode/prompts/v0.3.0/reviewer.md +225 -0
- package/presets/opencode/prompts/v0.3.0/task-coach.md +155 -0
- package/presets/opencode/prompts/v0.3.0/tester.md +251 -0
- package/presets/opencode/skills/android/SKILL.md +119 -0
- package/presets/opencode/skills/conductor-setup/SKILL.md +125 -0
- package/presets/opencode/skills/find-skills/SKILL.md +142 -0
- package/presets/opencode/skills/laravel-specialist/SKILL.md +264 -0
- package/presets/opencode/skills/laravel-specialist/references/eloquent.md +351 -0
- package/presets/opencode/skills/laravel-specialist/references/livewire.md +512 -0
- package/presets/opencode/skills/laravel-specialist/references/queues.md +423 -0
- package/presets/opencode/skills/laravel-specialist/references/routing.md +362 -0
- package/presets/opencode/skills/laravel-specialist/references/testing.md +522 -0
- package/presets/opencode/skills/multi-agent-orchestration/README.md +144 -0
- package/presets/opencode/skills/multi-agent-orchestration/SKILL.md +579 -0
- package/presets/opencode/skills/multi-agent-orchestration/examples/framework_implementations.py +362 -0
- package/presets/opencode/skills/multi-agent-orchestration/examples/orchestration_patterns.py +411 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/agent_communication.py +334 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/benchmarking.py +341 -0
- package/presets/opencode/skills/multi-agent-orchestration/scripts/workflow_management.py +334 -0
- package/presets/opencode/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/opencode/skills/pagespeed-insights/reference.md +50 -0
- package/presets/opencode/skills/pagespeed-perf/SKILL.md +279 -0
- package/presets/opencode/skills/php-pro/SKILL.md +208 -0
- package/presets/opencode/skills/php-pro/references/async-patterns.md +412 -0
- package/presets/opencode/skills/php-pro/references/laravel-patterns.md +377 -0
- package/presets/opencode/skills/php-pro/references/modern-php-features.md +323 -0
- package/presets/opencode/skills/php-pro/references/symfony-patterns.md +466 -0
- package/presets/opencode/skills/php-pro/references/testing-quality.md +466 -0
- package/presets/opencode/skills/workflow-orchestration-patterns/SKILL.md +98 -0
- package/presets/opencode/skills/workflow-orchestration-patterns/references/details.md +223 -0
- package/presets/seo-hotel/commands/cc-seo-audit.md +17 -9
- package/presets/seo-hotel/settings.json +225 -0
- package/presets/seo-hotel/skills/find-skills/SKILL.md +142 -0
- package/presets/seo-hotel/skills/pagespeed-insights/SKILL.md +443 -0
- package/presets/seo-hotel/skills/pagespeed-insights/reference.md +50 -0
- package/src/presets/manifests/agy.yml +38 -3
- package/src/presets/manifests/claude.yml +8 -2
- package/src/presets/manifests/codex.yml +3 -2
- package/src/presets/manifests/cursor.yml +3 -2
- package/src/presets/manifests/gemini.yml +3 -2
- package/src/presets/manifests/opencode.yml +7 -2
- package/src/presets/models/agy.yml +16 -0
- 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
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Multi-Agent Orchestration - Code Structure
|
|
2
|
+
|
|
3
|
+
This skill uses supporting Python files to keep documentation lean and maintainable.
|
|
4
|
+
|
|
5
|
+
## Directory Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
multi-agent-orchestration/
|
|
9
|
+
├── SKILL.md # Main documentation (patterns, concepts)
|
|
10
|
+
├── README.md # This file
|
|
11
|
+
├── examples/ # Implementation examples
|
|
12
|
+
│ ├── orchestration_patterns.py # Sequential, parallel, hierarchical, consensus
|
|
13
|
+
│ └── framework_implementations.py # CrewAI, AutoGen, LangGraph, Swarm templates
|
|
14
|
+
└── scripts/ # Utility modules
|
|
15
|
+
├── agent_communication.py # Message broker, shared memory, protocols
|
|
16
|
+
├── workflow_management.py # Workflow execution and optimization
|
|
17
|
+
└── benchmarking.py # Performance and collaboration metrics
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Running Examples
|
|
21
|
+
|
|
22
|
+
### 1. Orchestration Patterns
|
|
23
|
+
```bash
|
|
24
|
+
python examples/orchestration_patterns.py
|
|
25
|
+
```
|
|
26
|
+
Demonstrates sequential, parallel, hierarchical, and consensus orchestration.
|
|
27
|
+
|
|
28
|
+
### 2. Framework Templates
|
|
29
|
+
```bash
|
|
30
|
+
python examples/framework_implementations.py
|
|
31
|
+
```
|
|
32
|
+
Templates and configurations for CrewAI, AutoGen, LangGraph, and Swarm frameworks.
|
|
33
|
+
|
|
34
|
+
## Using the Utilities
|
|
35
|
+
|
|
36
|
+
### Agent Communication
|
|
37
|
+
```python
|
|
38
|
+
from scripts.agent_communication import MessageBroker, SharedMemory, CommunicationProtocol
|
|
39
|
+
|
|
40
|
+
# Set up communication
|
|
41
|
+
broker = MessageBroker()
|
|
42
|
+
shared_memory = SharedMemory()
|
|
43
|
+
protocol = CommunicationProtocol(broker, shared_memory)
|
|
44
|
+
|
|
45
|
+
# Send messages between agents
|
|
46
|
+
protocol.request_analysis("agent_a", "agent_b", "Analyze this topic")
|
|
47
|
+
|
|
48
|
+
# Share findings
|
|
49
|
+
protocol.share_findings("agent_a", "analysis_results", {"findings": "..."})
|
|
50
|
+
|
|
51
|
+
# Get communication stats
|
|
52
|
+
stats = broker.get_statistics()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Workflow Management
|
|
56
|
+
```python
|
|
57
|
+
from scripts.workflow_management import WorkflowExecutor, WorkflowOptimizer
|
|
58
|
+
|
|
59
|
+
# Create and execute workflow
|
|
60
|
+
executor = WorkflowExecutor()
|
|
61
|
+
workflow = executor.create_workflow("workflow_1", "Analysis Workflow")
|
|
62
|
+
|
|
63
|
+
# Add tasks
|
|
64
|
+
executor.add_task("workflow_1", "task_1", "researcher", "Research the topic")
|
|
65
|
+
executor.add_task("workflow_1", "task_2", "analyst", "Analyze findings", dependencies=["task_1"])
|
|
66
|
+
|
|
67
|
+
# Execute
|
|
68
|
+
results = executor.execute_workflow("workflow_1", executor_func)
|
|
69
|
+
|
|
70
|
+
# Analyze workflow
|
|
71
|
+
analysis = WorkflowOptimizer.analyze_dependencies(workflow)
|
|
72
|
+
print(f"Critical path: {analysis['critical_path']}")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Benchmarking
|
|
76
|
+
```python
|
|
77
|
+
from scripts.benchmarking import TeamBenchmark, AgentEffectiveness, CollaborationMetrics
|
|
78
|
+
|
|
79
|
+
# Benchmark team performance
|
|
80
|
+
benchmark = TeamBenchmark()
|
|
81
|
+
result = benchmark.run_benchmark("sequential_test", orchestrator, test_data)
|
|
82
|
+
|
|
83
|
+
# Track agent effectiveness
|
|
84
|
+
effectiveness = AgentEffectiveness()
|
|
85
|
+
effectiveness.record_agent_task("agent_a", "task_1", success=True, quality_score=0.95, duration=2.5)
|
|
86
|
+
|
|
87
|
+
# Get agent rankings
|
|
88
|
+
rankings = effectiveness.rank_agents()
|
|
89
|
+
for rank, agent, score, metrics in rankings:
|
|
90
|
+
print(f"{rank}. {agent}: {score:.2f}")
|
|
91
|
+
|
|
92
|
+
# Analyze collaboration
|
|
93
|
+
collaboration = CollaborationMetrics()
|
|
94
|
+
collaboration.record_interaction("agent_a", "agent_b", "request", response_time=0.5, successful=True)
|
|
95
|
+
interaction_metrics = collaboration.get_interaction_metrics()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Integration with SKILL.md
|
|
99
|
+
|
|
100
|
+
- SKILL.md contains conceptual information, orchestration patterns, and best practices
|
|
101
|
+
- Code examples are in `examples/` for clarity and runnable implementations
|
|
102
|
+
- Utilities are in `scripts/` for modular, reusable components
|
|
103
|
+
- This keeps token costs low while maintaining full functionality
|
|
104
|
+
|
|
105
|
+
## Orchestration Patterns Covered
|
|
106
|
+
|
|
107
|
+
1. **Sequential Orchestration** - Tasks execute one after another
|
|
108
|
+
2. **Parallel Orchestration** - Multiple agents work simultaneously
|
|
109
|
+
3. **Hierarchical Orchestration** - Manager coordinates specialist teams
|
|
110
|
+
4. **Consensus-Based** - Agents debate and reach consensus
|
|
111
|
+
5. **Adaptive Workflows** - Orchestration changes based on progress
|
|
112
|
+
6. **DAG-Based** - Workflow as directed acyclic graph
|
|
113
|
+
|
|
114
|
+
## Framework Implementations
|
|
115
|
+
|
|
116
|
+
- **CrewAI** - Clear roles, hierarchical structure
|
|
117
|
+
- **AutoGen** - Multi-turn conversations, group discussions
|
|
118
|
+
- **LangGraph** - State management, complex workflows
|
|
119
|
+
- **Swarm** - Simple handoffs, conversational workflows
|
|
120
|
+
|
|
121
|
+
## Key Features
|
|
122
|
+
|
|
123
|
+
- **Token Efficient**: Modular code structure reduces LLM context usage
|
|
124
|
+
- **Production Ready**: Includes monitoring, optimization, and benchmarking
|
|
125
|
+
- **Framework Agnostic**: Works with any agent framework
|
|
126
|
+
- **Communication Patterns**: Direct, tool-mediated, and manager-based
|
|
127
|
+
- **Performance Metrics**: Team and individual agent effectiveness tracking
|
|
128
|
+
|
|
129
|
+
## Communication Patterns
|
|
130
|
+
|
|
131
|
+
- **Direct Communication**: Agent-to-agent message passing
|
|
132
|
+
- **Tool-Mediated**: Agents use shared memory/database
|
|
133
|
+
- **Manager-Based**: Central coordinator manages communication
|
|
134
|
+
- **Broadcast**: One-to-many messaging
|
|
135
|
+
|
|
136
|
+
## Next Steps
|
|
137
|
+
|
|
138
|
+
1. Define agent roles and expertise
|
|
139
|
+
2. Choose orchestration pattern (sequential, parallel, hierarchical)
|
|
140
|
+
3. Select communication approach (direct, shared memory, manager)
|
|
141
|
+
4. Implement workflow with task definitions
|
|
142
|
+
5. Set up monitoring and metrics
|
|
143
|
+
6. Benchmark and optimize
|
|
144
|
+
7. Deploy and iterate
|