opencodekit 0.10.0 → 0.11.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.
- package/dist/index.js +1 -1
- package/dist/template/.opencode/agent/planner.md +3 -2
- package/dist/template/.opencode/command/accessibility-check.md +297 -30
- package/dist/template/.opencode/command/analyze-mockup.md +412 -20
- package/dist/template/.opencode/command/analyze-project.md +445 -30
- package/dist/template/.opencode/command/brainstorm.md +294 -5
- package/dist/template/.opencode/command/commit.md +231 -17
- package/dist/template/.opencode/command/create.md +415 -77
- package/dist/template/.opencode/command/design-audit.md +483 -29
- package/dist/template/.opencode/command/design.md +615 -6
- package/dist/template/.opencode/command/edit-image.md +223 -20
- package/dist/template/.opencode/command/finish.md +163 -71
- package/dist/template/.opencode/command/fix-ci.md +297 -24
- package/dist/template/.opencode/command/fix-types.md +351 -13
- package/dist/template/.opencode/command/fix-ui.md +299 -13
- package/dist/template/.opencode/command/fix.md +262 -9
- package/dist/template/.opencode/command/generate-diagram.md +327 -26
- package/dist/template/.opencode/command/generate-icon.md +266 -22
- package/dist/template/.opencode/command/generate-image.md +232 -12
- package/dist/template/.opencode/command/generate-pattern.md +234 -20
- package/dist/template/.opencode/command/generate-storyboard.md +231 -21
- package/dist/template/.opencode/command/handoff.md +208 -31
- package/dist/template/.opencode/command/implement.md +163 -50
- package/dist/template/.opencode/command/import-plan.md +253 -52
- package/dist/template/.opencode/command/init.md +154 -35
- package/dist/template/.opencode/command/integration-test.md +410 -24
- package/dist/template/.opencode/command/issue.md +177 -21
- package/dist/template/.opencode/command/new-feature.md +390 -54
- package/dist/template/.opencode/command/plan.md +394 -107
- package/dist/template/.opencode/command/pr.md +235 -29
- package/dist/template/.opencode/command/quick-build.md +234 -5
- package/dist/template/.opencode/command/research-and-implement.md +442 -12
- package/dist/template/.opencode/command/research-ui.md +444 -34
- package/dist/template/.opencode/command/research.md +179 -45
- package/dist/template/.opencode/command/restore-image.md +416 -22
- package/dist/template/.opencode/command/resume.md +447 -63
- package/dist/template/.opencode/command/revert-feature.md +347 -65
- package/dist/template/.opencode/command/review-codebase.md +199 -4
- package/dist/template/.opencode/command/skill-create.md +506 -14
- package/dist/template/.opencode/command/skill-optimize.md +487 -16
- package/dist/template/.opencode/command/status.md +326 -60
- package/dist/template/.opencode/command/summarize.md +374 -33
- package/dist/template/.opencode/command/triage.md +361 -0
- package/dist/template/.opencode/command/ui-review.md +296 -25
- package/dist/template/.opencode/skill/beads/SKILL.md +108 -3
- package/dist/template/.opencode/skill/playwriter/SKILL.md +148 -0
- package/package.json +1 -1
|
@@ -1,40 +1,426 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Create integration tests within task constraints
|
|
3
|
-
argument-hint: "<bead-id>"
|
|
3
|
+
argument-hint: "<bead-id|path> [--pattern=<pattern>] [--framework=<framework>]"
|
|
4
4
|
agent: build
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Integration Test: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Create integration tests that verify module boundaries and system interactions.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
- `skill({ name: "condition-based-waiting" })` (for async tests)
|
|
13
|
-
- `skill({ name: "testing-anti-patterns" })` (avoid common mistakes)
|
|
11
|
+
## Load Skills
|
|
14
12
|
|
|
15
|
-
|
|
13
|
+
```typescript
|
|
14
|
+
skill({ name: "beads" }); // Session protocol
|
|
15
|
+
skill({ name: "test-driven-development" });
|
|
16
|
+
```
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
```typescript
|
|
19
|
+
skill({ name: "test-driven-development" });
|
|
20
|
+
skill({ name: "condition-based-waiting" }); // For async tests
|
|
21
|
+
skill({ name: "testing-anti-patterns" }); // Avoid common mistakes
|
|
22
|
+
```
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## What Are Integration Tests?
|
|
27
|
+
|
|
28
|
+
| Test Type | Scope | Speed | Dependencies |
|
|
29
|
+
| --------------- | --------------------------- | ------------ | -------------------- |
|
|
30
|
+
| **Unit** | Single function/class | Fast (ms) | All mocked |
|
|
31
|
+
| **Integration** | Module boundaries, APIs, DB | Medium (s) | Real or test doubles |
|
|
32
|
+
| **E2E** | Full user flows | Slow (s-min) | Real everything |
|
|
33
|
+
|
|
34
|
+
**Integration tests verify:**
|
|
35
|
+
|
|
36
|
+
- API endpoints work end-to-end
|
|
37
|
+
- Database queries return correct data
|
|
38
|
+
- Services communicate correctly
|
|
39
|
+
- External integrations behave as expected
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Phase 1: Task Validation
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Check bead exists
|
|
47
|
+
bd_show({ id: "$ARGUMENTS" });
|
|
48
|
+
|
|
49
|
+
// Read test constraints
|
|
50
|
+
read(".beads/artifacts/$ARGUMENTS/spec.md");
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If bead missing: STOP. Create with `/create` first.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## Phase 2: Framework Detection
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# Detect test framework
|
|
61
|
+
glob pattern="**/jest.config.*"
|
|
62
|
+
glob pattern="**/vitest.config.*"
|
|
63
|
+
glob pattern="**/pytest.ini"
|
|
64
|
+
glob pattern="**/pyproject.toml"
|
|
65
|
+
|
|
66
|
+
# Read package.json for test command
|
|
67
|
+
read package.json
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Framework | File Pattern | Test Command |
|
|
71
|
+
| --------- | ------------------------ | ------------ |
|
|
72
|
+
| Jest | `*.test.ts`, `*.spec.ts` | `npm test` |
|
|
73
|
+
| Vitest | `*.test.ts`, `*.spec.ts` | `npm test` |
|
|
74
|
+
| pytest | `test_*.py`, `*_test.py` | `pytest` |
|
|
75
|
+
| Go | `*_test.go` | `go test` |
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Phase 3: Test Structure
|
|
80
|
+
|
|
81
|
+
### File Location
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
src/
|
|
85
|
+
├── auth/
|
|
86
|
+
│ ├── login.ts
|
|
87
|
+
│ └── login.test.ts # Co-located unit tests
|
|
88
|
+
tests/
|
|
89
|
+
├── integration/
|
|
90
|
+
│ ├── auth.test.ts # Integration tests here
|
|
91
|
+
│ ├── api.test.ts
|
|
92
|
+
│ └── database.test.ts
|
|
93
|
+
└── fixtures/
|
|
94
|
+
├── users.json
|
|
95
|
+
└── factories.ts
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Test File Structure
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// tests/integration/auth.test.ts
|
|
102
|
+
|
|
103
|
+
import { describe, it, expect, beforeAll, afterAll, beforeEach } from "vitest";
|
|
104
|
+
import { createTestDatabase, cleanupDatabase } from "../fixtures/database";
|
|
105
|
+
import { createTestUser } from "../fixtures/factories";
|
|
106
|
+
import { app } from "../../src/app";
|
|
107
|
+
|
|
108
|
+
describe("Auth Integration", () => {
|
|
109
|
+
let db: TestDatabase;
|
|
110
|
+
|
|
111
|
+
beforeAll(async () => {
|
|
112
|
+
db = await createTestDatabase();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
afterAll(async () => {
|
|
116
|
+
await cleanupDatabase(db);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
beforeEach(async () => {
|
|
120
|
+
await db.clear(); // Clean slate each test
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe("POST /login", () => {
|
|
124
|
+
it("returns JWT for valid credentials", async () => {
|
|
125
|
+
// Arrange
|
|
126
|
+
const user = await createTestUser(db, { email: "test@example.com" });
|
|
127
|
+
|
|
128
|
+
// Act
|
|
129
|
+
const response = await app.request("/login", {
|
|
130
|
+
method: "POST",
|
|
131
|
+
body: JSON.stringify({ email: user.email, password: "password123" }),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Assert
|
|
135
|
+
expect(response.status).toBe(200);
|
|
136
|
+
const body = await response.json();
|
|
137
|
+
expect(body.token).toBeDefined();
|
|
138
|
+
expect(body.user.email).toBe(user.email);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("returns 401 for invalid password", async () => {
|
|
142
|
+
const user = await createTestUser(db);
|
|
143
|
+
|
|
144
|
+
const response = await app.request("/login", {
|
|
145
|
+
method: "POST",
|
|
146
|
+
body: JSON.stringify({ email: user.email, password: "wrong" }),
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
expect(response.status).toBe(401);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Phase 4: Common Test Patterns
|
|
158
|
+
|
|
159
|
+
### Database Integration
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
describe("User Repository", () => {
|
|
163
|
+
let db: Database;
|
|
164
|
+
|
|
165
|
+
beforeAll(async () => {
|
|
166
|
+
db = await createTestDatabase();
|
|
167
|
+
await db.migrate();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
afterEach(async () => {
|
|
171
|
+
await db.exec("DELETE FROM users"); // Clean between tests
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
afterAll(async () => {
|
|
175
|
+
await db.close();
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("creates user with hashed password", async () => {
|
|
179
|
+
const repo = new UserRepository(db);
|
|
180
|
+
|
|
181
|
+
const user = await repo.create({
|
|
182
|
+
email: "test@example.com",
|
|
183
|
+
password: "plaintext123",
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
expect(user.id).toBeDefined();
|
|
187
|
+
expect(user.password).not.toBe("plaintext123"); // Should be hashed
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### API Integration
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
describe("API Integration", () => {
|
|
196
|
+
let server: TestServer;
|
|
197
|
+
|
|
198
|
+
beforeAll(async () => {
|
|
199
|
+
server = await createTestServer();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
afterAll(async () => {
|
|
203
|
+
await server.close();
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("GET /users returns paginated list", async () => {
|
|
207
|
+
// Seed data
|
|
208
|
+
await seedUsers(10);
|
|
209
|
+
|
|
210
|
+
const response = await fetch(`${server.url}/users?page=1&limit=5`);
|
|
211
|
+
const data = await response.json();
|
|
212
|
+
|
|
213
|
+
expect(response.status).toBe(200);
|
|
214
|
+
expect(data.users).toHaveLength(5);
|
|
215
|
+
expect(data.total).toBe(10);
|
|
216
|
+
expect(data.page).toBe(1);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### External Service Integration
|
|
22
222
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- Implement minimal code to pass
|
|
28
|
-
- Refactor while green
|
|
29
|
-
3. **Test only task integration points** from spec architecture
|
|
223
|
+
```typescript
|
|
224
|
+
describe("Payment Service", () => {
|
|
225
|
+
it("processes payment with Stripe test mode", async () => {
|
|
226
|
+
const stripe = new Stripe(process.env.STRIPE_TEST_KEY);
|
|
30
227
|
|
|
31
|
-
|
|
228
|
+
const paymentIntent = await stripe.paymentIntents.create({
|
|
229
|
+
amount: 1000,
|
|
230
|
+
currency: "usd",
|
|
231
|
+
payment_method: "pm_card_visa", // Stripe test card
|
|
232
|
+
confirm: true,
|
|
233
|
+
});
|
|
32
234
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
235
|
+
expect(paymentIntent.status).toBe("succeeded");
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Async/Queue Integration
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
describe("Job Queue", () => {
|
|
244
|
+
it("processes email job within timeout", async () => {
|
|
245
|
+
const queue = createTestQueue();
|
|
246
|
+
|
|
247
|
+
// Add job
|
|
248
|
+
await queue.add("send-email", { to: "test@example.com" });
|
|
249
|
+
|
|
250
|
+
// Wait for processing (use condition-based-waiting skill)
|
|
251
|
+
await waitFor(
|
|
252
|
+
async () => {
|
|
253
|
+
const job = await queue.getJob("send-email");
|
|
254
|
+
return job?.status === "completed";
|
|
255
|
+
},
|
|
256
|
+
{ timeout: 5000, interval: 100 },
|
|
257
|
+
);
|
|
258
|
+
|
|
259
|
+
const job = await queue.getJob("send-email");
|
|
260
|
+
expect(job.status).toBe("completed");
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Phase 5: Test Data Management
|
|
268
|
+
|
|
269
|
+
### Factories
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// tests/fixtures/factories.ts
|
|
273
|
+
|
|
274
|
+
export function createTestUser(db: Database, overrides = {}) {
|
|
275
|
+
return db.insert("users", {
|
|
276
|
+
id: randomUUID(),
|
|
277
|
+
email: `test-${Date.now()}@example.com`,
|
|
278
|
+
password: hashSync("password123", 10),
|
|
279
|
+
createdAt: new Date(),
|
|
280
|
+
...overrides,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function createTestOrder(db: Database, userId: string, overrides = {}) {
|
|
285
|
+
return db.insert("orders", {
|
|
286
|
+
id: randomUUID(),
|
|
287
|
+
userId,
|
|
288
|
+
status: "pending",
|
|
289
|
+
total: 100,
|
|
290
|
+
...overrides,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Cleanup Strategies
|
|
296
|
+
|
|
297
|
+
| Strategy | Pros | Cons |
|
|
298
|
+
| ------------------------ | ----------- | ------------------ |
|
|
299
|
+
| **Transaction rollback** | Fast, clean | Complex setup |
|
|
300
|
+
| **DELETE after each** | Simple | Slower |
|
|
301
|
+
| **Fresh DB per test** | Isolated | Very slow |
|
|
302
|
+
| **Truncate tables** | Fast reset | May miss FK issues |
|
|
303
|
+
|
|
304
|
+
**Recommended:** Transaction rollback for speed, DELETE for simplicity.
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Phase 6: Isolation Patterns
|
|
309
|
+
|
|
310
|
+
### Database Isolation
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
// Wrap each test in transaction that rolls back
|
|
314
|
+
beforeEach(async () => {
|
|
315
|
+
await db.exec("BEGIN");
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
afterEach(async () => {
|
|
319
|
+
await db.exec("ROLLBACK");
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### Port Isolation (Parallel Tests)
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
// Use dynamic ports for parallel test runners
|
|
327
|
+
const server = await app.listen(0); // Random available port
|
|
328
|
+
const port = server.address().port;
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Environment Isolation
|
|
332
|
+
|
|
333
|
+
```bash
|
|
334
|
+
# .env.test
|
|
335
|
+
DATABASE_URL=postgres://localhost/myapp_test
|
|
336
|
+
STRIPE_KEY=sk_test_xxx
|
|
337
|
+
REDIS_URL=redis://localhost:6379/1 # Separate DB number
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## Phase 7: TDD Workflow
|
|
343
|
+
|
|
344
|
+
Follow the cycle:
|
|
345
|
+
|
|
346
|
+
1. **Write failing test first**
|
|
347
|
+
- Test should fail for the RIGHT reason
|
|
348
|
+
- Not a syntax error, but missing functionality
|
|
349
|
+
|
|
350
|
+
2. **Verify failure message**
|
|
351
|
+
- Should clearly indicate what's missing
|
|
352
|
+
- "Expected 200, got 404" = endpoint missing
|
|
353
|
+
|
|
354
|
+
3. **Implement minimal code**
|
|
355
|
+
- Just enough to pass
|
|
356
|
+
- Don't over-engineer
|
|
357
|
+
|
|
358
|
+
4. **Refactor while green**
|
|
359
|
+
- Improve code quality
|
|
360
|
+
- Keep tests passing
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## Anti-Patterns to Avoid
|
|
365
|
+
|
|
366
|
+
| Anti-Pattern | Problem | Do Instead |
|
|
367
|
+
| ------------------------------ | --------------------------- | --------------------------------- |
|
|
368
|
+
| Testing implementation details | Brittle tests | Test behavior/outcomes |
|
|
369
|
+
| Excessive mocking | Tests don't reflect reality | Use real dependencies |
|
|
370
|
+
| Shared mutable state | Flaky tests | Isolate each test |
|
|
371
|
+
| Testing third-party code | Waste of time | Trust libraries, test integration |
|
|
372
|
+
| No cleanup | Tests affect each other | Always clean up |
|
|
373
|
+
| Hardcoded test data | Fragile | Use factories |
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
## Coverage Guidelines
|
|
378
|
+
|
|
379
|
+
| Coverage Type | Target | Notes |
|
|
380
|
+
| -------------------- | --------- | ----------------------------- |
|
|
381
|
+
| Line coverage | 70-80% | Higher for critical paths |
|
|
382
|
+
| Branch coverage | 60-70% | Cover main branches |
|
|
383
|
+
| Integration coverage | Key paths | All API endpoints, main flows |
|
|
384
|
+
|
|
385
|
+
**Focus on:** Happy paths, error cases, edge cases in that order.
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## CI Considerations
|
|
390
|
+
|
|
391
|
+
```yaml
|
|
392
|
+
# .github/workflows/test.yml
|
|
393
|
+
jobs:
|
|
394
|
+
integration-tests:
|
|
395
|
+
services:
|
|
396
|
+
postgres:
|
|
397
|
+
image: postgres:15
|
|
398
|
+
env:
|
|
399
|
+
POSTGRES_DB: test
|
|
400
|
+
steps:
|
|
401
|
+
- run: npm run test:integration
|
|
402
|
+
env:
|
|
403
|
+
DATABASE_URL: postgres://postgres@localhost/test
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
---
|
|
407
|
+
|
|
408
|
+
## Output
|
|
409
|
+
|
|
410
|
+
After writing tests:
|
|
411
|
+
|
|
412
|
+
1. **Run tests**: Verify all pass
|
|
413
|
+
2. **Check coverage**: Meet guidelines
|
|
414
|
+
3. **Update review.md**: `.beads/artifacts/$ARGUMENTS/review.md`
|
|
415
|
+
4. **Complete**: `/finish $ARGUMENTS`
|
|
416
|
+
|
|
417
|
+
---
|
|
37
418
|
|
|
38
|
-
##
|
|
419
|
+
## Related Commands
|
|
39
420
|
|
|
40
|
-
|
|
421
|
+
| Need | Command |
|
|
422
|
+
| ------------------- | ------------------------- |
|
|
423
|
+
| Create unit tests | Use TDD skill directly |
|
|
424
|
+
| Fix failing tests | `/fix` |
|
|
425
|
+
| Review test quality | `/review-codebase tests/` |
|
|
426
|
+
| Complete task | `/finish <bead-id>` |
|
|
@@ -1,37 +1,121 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Analyze GitHub issue and create bead for tracking
|
|
3
|
-
argument-hint: "
|
|
3
|
+
argument-hint: "<issue-number>"
|
|
4
4
|
agent: build
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Analyze Issue: $ARGUMENTS
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Load Beads Skill
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
skill({ name: "beads" });
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Phase 1: Check for Duplicates
|
|
16
|
+
|
|
17
|
+
Before creating, search for existing beads:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
bd_ls({ status: "all", limit: 20 });
|
|
21
|
+
memory - search({ query: "[keywords from issue title]" });
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If similar bead exists:
|
|
25
|
+
|
|
26
|
+
- Link as related, or
|
|
27
|
+
- Add to existing bead, or
|
|
28
|
+
- Confirm this is intentionally separate
|
|
29
|
+
|
|
30
|
+
## Phase 2: Fetch GitHub Issue
|
|
10
31
|
|
|
11
32
|
```bash
|
|
12
|
-
gh issue view $ARGUMENTS
|
|
33
|
+
gh issue view $ARGUMENTS --json title,body,labels,state,assignees,milestone
|
|
13
34
|
```
|
|
14
35
|
|
|
15
|
-
|
|
36
|
+
Extract:
|
|
37
|
+
|
|
38
|
+
- **Title**: Issue title
|
|
39
|
+
- **Labels**: For tag mapping
|
|
40
|
+
- **Body**: For analysis
|
|
41
|
+
|
|
42
|
+
## Phase 3: Analysis
|
|
43
|
+
|
|
44
|
+
Parse the issue content:
|
|
45
|
+
|
|
46
|
+
| Field | Extract From |
|
|
47
|
+
| ------------ | ------------------------------- |
|
|
48
|
+
| **Problem** | What's broken/needed? |
|
|
49
|
+
| **Expected** | What should happen? |
|
|
50
|
+
| **Current** | What happens now? |
|
|
51
|
+
| **Steps** | How to reproduce? |
|
|
52
|
+
| **Files** | Mentioned files or components |
|
|
53
|
+
| **Labels** | bug, feature, enhancement, etc. |
|
|
16
54
|
|
|
17
|
-
|
|
18
|
-
2. **Expected:** What should happen?
|
|
19
|
-
3. **Current:** What happens now?
|
|
20
|
-
4. **Steps:** How to reproduce?
|
|
55
|
+
## Phase 4: Map Labels & Priority
|
|
21
56
|
|
|
22
|
-
|
|
57
|
+
**Label → Tag mapping:**
|
|
23
58
|
|
|
24
|
-
|
|
59
|
+
| GitHub Label | Bead Tag |
|
|
60
|
+
| ------------- | -------- |
|
|
61
|
+
| bug | bug |
|
|
62
|
+
| enhancement | feature |
|
|
63
|
+
| feature | feature |
|
|
64
|
+
| documentation | docs |
|
|
65
|
+
| frontend, ui | fe |
|
|
66
|
+
| backend, api | be |
|
|
67
|
+
| mobile | mobile |
|
|
68
|
+
| devops, infra | devops |
|
|
69
|
+
| testing | qa |
|
|
70
|
+
|
|
71
|
+
**Priority mapping:**
|
|
72
|
+
|
|
73
|
+
| GitHub Signal | Bead Priority |
|
|
74
|
+
| ------------------------- | ------------- |
|
|
75
|
+
| critical, P0, blocker | 0 |
|
|
76
|
+
| high, P1, urgent | 1 |
|
|
77
|
+
| medium, P2 (default) | 2 |
|
|
78
|
+
| low, P3 | 3 |
|
|
79
|
+
| backlog, P4, nice-to-have | 4 |
|
|
80
|
+
|
|
81
|
+
## Phase 5: Estimate Complexity
|
|
82
|
+
|
|
83
|
+
Based on issue analysis:
|
|
84
|
+
|
|
85
|
+
| Signals | Estimate | Next Step |
|
|
86
|
+
| ------------------------------------- | -------- | ---------- |
|
|
87
|
+
| Single file, obvious fix, clear repro | S (~10) | /implement |
|
|
88
|
+
| Few files, clear scope, known area | M (~30) | /implement |
|
|
89
|
+
| Multiple files, needs investigation | L (~100) | /research |
|
|
90
|
+
| Vague, architectural, cross-cutting | XL | Decompose |
|
|
91
|
+
|
|
92
|
+
## Phase 6: Create Tracking Bead
|
|
93
|
+
|
|
94
|
+
Reserve spec file:
|
|
25
95
|
|
|
26
96
|
```typescript
|
|
27
|
-
|
|
97
|
+
bd_reserve({
|
|
98
|
+
paths: [".beads/artifacts/<bead-id>/spec.md"],
|
|
99
|
+
reason: "Creating issue bead",
|
|
100
|
+
ttl: 600,
|
|
101
|
+
});
|
|
28
102
|
```
|
|
29
103
|
|
|
30
|
-
|
|
104
|
+
Create bead with mapped values:
|
|
31
105
|
|
|
32
|
-
|
|
106
|
+
```typescript
|
|
107
|
+
bd_add({
|
|
108
|
+
title: "<issue title>",
|
|
109
|
+
type: "[bug|feature|task]", // from label mapping
|
|
110
|
+
pri: [0 - 4], // from priority mapping
|
|
111
|
+
tags: ["[role]", "[estimate]"], // e.g., ["fe", "M"]
|
|
112
|
+
desc: "GitHub Issue #$ARGUMENTS",
|
|
113
|
+
});
|
|
114
|
+
```
|
|
33
115
|
|
|
34
|
-
|
|
116
|
+
## Phase 7: Create Spec
|
|
117
|
+
|
|
118
|
+
Use `.opencode/memory/_templates/prd.md` as base structure.
|
|
35
119
|
|
|
36
120
|
Save to `.beads/artifacts/<bead-id>/spec.md`:
|
|
37
121
|
|
|
@@ -42,6 +126,7 @@ Save to `.beads/artifacts/<bead-id>/spec.md`:
|
|
|
42
126
|
**Created:** [date]
|
|
43
127
|
**Status:** To Do
|
|
44
128
|
**GitHub Issue:** #$ARGUMENTS
|
|
129
|
+
**Estimate:** [S/M/L/XL] (~[N] tool calls)
|
|
45
130
|
|
|
46
131
|
## Goal
|
|
47
132
|
|
|
@@ -49,12 +134,12 @@ Save to `.beads/artifacts/<bead-id>/spec.md`:
|
|
|
49
134
|
|
|
50
135
|
## Scope
|
|
51
136
|
|
|
52
|
-
|
|
137
|
+
**In-Scope:**
|
|
53
138
|
|
|
54
139
|
- [Files to change]
|
|
55
140
|
- [Specific functionality to fix/add]
|
|
56
141
|
|
|
57
|
-
|
|
142
|
+
**Out-of-Scope:**
|
|
58
143
|
|
|
59
144
|
- [What we are NOT touching]
|
|
60
145
|
|
|
@@ -65,9 +150,22 @@ Save to `.beads/artifacts/<bead-id>/spec.md`:
|
|
|
65
150
|
|
|
66
151
|
## Success Criteria
|
|
67
152
|
|
|
68
|
-
- [ ] [
|
|
69
|
-
- [
|
|
70
|
-
- [ ] [
|
|
153
|
+
- [ ] [Criterion 1]
|
|
154
|
+
- Verify: `[actual command to test]`
|
|
155
|
+
- [ ] [Criterion 2]
|
|
156
|
+
- Verify: `[actual command to test]`
|
|
157
|
+
- [ ] No regression in related functionality
|
|
158
|
+
- Verify: `npm test`
|
|
159
|
+
|
|
160
|
+
## Constraints
|
|
161
|
+
|
|
162
|
+
**Must:**
|
|
163
|
+
|
|
164
|
+
- [Required constraint from issue]
|
|
165
|
+
|
|
166
|
+
**Never:**
|
|
167
|
+
|
|
168
|
+
- [Anti-pattern or forbidden action]
|
|
71
169
|
|
|
72
170
|
## Dependencies
|
|
73
171
|
|
|
@@ -77,11 +175,62 @@ Save to `.beads/artifacts/<bead-id>/spec.md`:
|
|
|
77
175
|
|
|
78
176
|
- **Risks/edge cases:** [What could go wrong]
|
|
79
177
|
- **Testing strategy:** [How to verify fix]
|
|
178
|
+
- **Related issues:** [Link to related GitHub issues]
|
|
80
179
|
```
|
|
81
180
|
|
|
181
|
+
## Phase 8: Comment on GitHub Issue
|
|
182
|
+
|
|
183
|
+
Add bead reference back to GitHub:
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
gh issue comment $ARGUMENTS --body "Tracking: \`<bead-id>\`
|
|
187
|
+
|
|
188
|
+
Estimate: [S/M/L/XL]
|
|
189
|
+
Next: [/implement or /research]"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Phase 9: Assign Role (optional)
|
|
193
|
+
|
|
194
|
+
For multi-agent workflows:
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
bd_assign({ id: "<bead-id>", role: "[fe/be/mobile/devops/qa]", notify: true });
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Phase 10: Sync & Report
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
bd_release({ _: true });
|
|
204
|
+
bd_sync({ reason: "Created bead for issue #$ARGUMENTS" });
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```
|
|
208
|
+
Issue Imported: #$ARGUMENTS
|
|
209
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
210
|
+
|
|
211
|
+
Bead: <bead-id>
|
|
212
|
+
Type: [bug/feature/task]
|
|
213
|
+
Priority: [0-4]
|
|
214
|
+
Estimate: [S/M/L/XL] (~[N] tool calls)
|
|
215
|
+
|
|
216
|
+
Labels mapped: [list]
|
|
217
|
+
Tags: [list]
|
|
218
|
+
|
|
219
|
+
Spec: .beads/artifacts/<bead-id>/spec.md
|
|
220
|
+
GitHub: Commented with bead reference ✓
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Next steps by estimate:**
|
|
224
|
+
|
|
225
|
+
| Estimate | Command |
|
|
226
|
+
| -------- | ---------------------- |
|
|
227
|
+
| S/M | `/implement <bead-id>` |
|
|
228
|
+
| L | `/research <bead-id>` |
|
|
229
|
+
| XL | Decompose first |
|
|
230
|
+
|
|
82
231
|
## Discovered Work
|
|
83
232
|
|
|
84
|
-
If analysis reveals additional issues
|
|
233
|
+
If analysis reveals additional issues:
|
|
85
234
|
|
|
86
235
|
```typescript
|
|
87
236
|
bd_add({
|
|
@@ -89,7 +238,14 @@ bd_add({
|
|
|
89
238
|
type: "task",
|
|
90
239
|
pri: 2,
|
|
91
240
|
parent: "<parent-bead-id>",
|
|
241
|
+
tags: ["[role]", "[estimate]"],
|
|
92
242
|
});
|
|
93
243
|
```
|
|
94
244
|
|
|
95
|
-
|
|
245
|
+
Report discovered work:
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
Discovered Work:
|
|
249
|
+
- <child-bead-id>: [title] ([estimate])
|
|
250
|
+
- <child-bead-id>: [title] ([estimate])
|
|
251
|
+
```
|