mcp-subagents-opencode 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +602 -0
- package/build/config/timeouts.d.ts +9 -0
- package/build/config/timeouts.d.ts.map +1 -0
- package/build/config/timeouts.js +18 -0
- package/build/config/timeouts.js.map +1 -0
- package/build/helpers.d.ts +6 -0
- package/build/helpers.d.ts.map +1 -0
- package/build/helpers.js +47 -0
- package/build/helpers.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +245 -0
- package/build/index.js.map +1 -0
- package/build/models.d.ts +32 -0
- package/build/models.d.ts.map +1 -0
- package/build/models.js +58 -0
- package/build/models.js.map +1 -0
- package/build/server/register-notifications.d.ts +3 -0
- package/build/server/register-notifications.d.ts.map +1 -0
- package/build/server/register-notifications.js +77 -0
- package/build/server/register-notifications.js.map +1 -0
- package/build/server/register-resources.d.ts +3 -0
- package/build/server/register-resources.d.ts.map +1 -0
- package/build/server/register-resources.js +210 -0
- package/build/server/register-resources.js.map +1 -0
- package/build/server/register-retry-execution.d.ts +2 -0
- package/build/server/register-retry-execution.d.ts.map +1 -0
- package/build/server/register-retry-execution.js +28 -0
- package/build/server/register-retry-execution.js.map +1 -0
- package/build/server/register-tasks.d.ts +3 -0
- package/build/server/register-tasks.d.ts.map +1 -0
- package/build/server/register-tasks.js +52 -0
- package/build/server/register-tasks.js.map +1 -0
- package/build/server/register-tools.d.ts +3 -0
- package/build/server/register-tools.d.ts.map +1 -0
- package/build/server/register-tools.js +32 -0
- package/build/server/register-tools.js.map +1 -0
- package/build/server/resource-helpers.d.ts +21 -0
- package/build/server/resource-helpers.d.ts.map +1 -0
- package/build/server/resource-helpers.js +84 -0
- package/build/server/resource-helpers.js.map +1 -0
- package/build/services/account-manager.d.ts +88 -0
- package/build/services/account-manager.d.ts.map +1 -0
- package/build/services/account-manager.js +239 -0
- package/build/services/account-manager.js.map +1 -0
- package/build/services/claude-code-runner.d.ts +15 -0
- package/build/services/claude-code-runner.d.ts.map +1 -0
- package/build/services/claude-code-runner.js +475 -0
- package/build/services/claude-code-runner.js.map +1 -0
- package/build/services/client-context.d.ts +31 -0
- package/build/services/client-context.d.ts.map +1 -0
- package/build/services/client-context.js +44 -0
- package/build/services/client-context.js.map +1 -0
- package/build/services/exhaustion-fallback.d.ts +27 -0
- package/build/services/exhaustion-fallback.d.ts.map +1 -0
- package/build/services/exhaustion-fallback.js +30 -0
- package/build/services/exhaustion-fallback.js.map +1 -0
- package/build/services/fallback-orchestrator.d.ts +16 -0
- package/build/services/fallback-orchestrator.d.ts.map +1 -0
- package/build/services/fallback-orchestrator.js +48 -0
- package/build/services/fallback-orchestrator.js.map +1 -0
- package/build/services/opencode-client.d.ts +40 -0
- package/build/services/opencode-client.d.ts.map +1 -0
- package/build/services/opencode-client.js +147 -0
- package/build/services/opencode-client.js.map +1 -0
- package/build/services/opencode-spawner.d.ts +56 -0
- package/build/services/opencode-spawner.d.ts.map +1 -0
- package/build/services/opencode-spawner.js +426 -0
- package/build/services/opencode-spawner.js.map +1 -0
- package/build/services/output-file.d.ts +24 -0
- package/build/services/output-file.d.ts.map +1 -0
- package/build/services/output-file.js +90 -0
- package/build/services/output-file.js.map +1 -0
- package/build/services/progress-registry.d.ts +12 -0
- package/build/services/progress-registry.d.ts.map +1 -0
- package/build/services/progress-registry.js +97 -0
- package/build/services/progress-registry.js.map +1 -0
- package/build/services/question-registry.d.ts +79 -0
- package/build/services/question-registry.d.ts.map +1 -0
- package/build/services/question-registry.js +249 -0
- package/build/services/question-registry.js.map +1 -0
- package/build/services/retry-queue.d.ts +41 -0
- package/build/services/retry-queue.d.ts.map +1 -0
- package/build/services/retry-queue.js +195 -0
- package/build/services/retry-queue.js.map +1 -0
- package/build/services/sdk-client-manager.d.ts +149 -0
- package/build/services/sdk-client-manager.d.ts.map +1 -0
- package/build/services/sdk-client-manager.js +632 -0
- package/build/services/sdk-client-manager.js.map +1 -0
- package/build/services/sdk-session-adapter.d.ts +203 -0
- package/build/services/sdk-session-adapter.d.ts.map +1 -0
- package/build/services/sdk-session-adapter.js +1088 -0
- package/build/services/sdk-session-adapter.js.map +1 -0
- package/build/services/sdk-spawner.d.ts +42 -0
- package/build/services/sdk-spawner.d.ts.map +1 -0
- package/build/services/sdk-spawner.js +488 -0
- package/build/services/sdk-spawner.js.map +1 -0
- package/build/services/session-hooks.d.ts +24 -0
- package/build/services/session-hooks.d.ts.map +1 -0
- package/build/services/session-hooks.js +130 -0
- package/build/services/session-hooks.js.map +1 -0
- package/build/services/session-snapshot.d.ts +19 -0
- package/build/services/session-snapshot.d.ts.map +1 -0
- package/build/services/session-snapshot.js +203 -0
- package/build/services/session-snapshot.js.map +1 -0
- package/build/services/subscription-registry.d.ts +12 -0
- package/build/services/subscription-registry.d.ts.map +1 -0
- package/build/services/subscription-registry.js +27 -0
- package/build/services/subscription-registry.js.map +1 -0
- package/build/services/task-manager.d.ts +150 -0
- package/build/services/task-manager.d.ts.map +1 -0
- package/build/services/task-manager.js +765 -0
- package/build/services/task-manager.js.map +1 -0
- package/build/services/task-persistence.d.ts +29 -0
- package/build/services/task-persistence.d.ts.map +1 -0
- package/build/services/task-persistence.js +159 -0
- package/build/services/task-persistence.js.map +1 -0
- package/build/services/task-status-mapper.d.ts +21 -0
- package/build/services/task-status-mapper.d.ts.map +1 -0
- package/build/services/task-status-mapper.js +171 -0
- package/build/services/task-status-mapper.js.map +1 -0
- package/build/templates/index.d.ts +22 -0
- package/build/templates/index.d.ts.map +1 -0
- package/build/templates/index.js +147 -0
- package/build/templates/index.js.map +1 -0
- package/build/templates/overlays/coder-csharp.mdx +58 -0
- package/build/templates/overlays/coder-go.mdx +53 -0
- package/build/templates/overlays/coder-java.mdx +54 -0
- package/build/templates/overlays/coder-kotlin.mdx +56 -0
- package/build/templates/overlays/coder-nextjs.mdx +65 -0
- package/build/templates/overlays/coder-python.mdx +53 -0
- package/build/templates/overlays/coder-react.mdx +55 -0
- package/build/templates/overlays/coder-ruby.mdx +59 -0
- package/build/templates/overlays/coder-rust.mdx +48 -0
- package/build/templates/overlays/coder-supabase.mdx +268 -0
- package/build/templates/overlays/coder-supastarter.mdx +313 -0
- package/build/templates/overlays/coder-swift.mdx +56 -0
- package/build/templates/overlays/coder-tauri.mdx +566 -0
- package/build/templates/overlays/coder-triggerdev.mdx +296 -0
- package/build/templates/overlays/coder-typescript.mdx +45 -0
- package/build/templates/overlays/coder-vue.mdx +62 -0
- package/build/templates/overlays/planner-architecture.mdx +78 -0
- package/build/templates/overlays/planner-bugfix.mdx +36 -0
- package/build/templates/overlays/planner-feature.mdx +38 -0
- package/build/templates/overlays/planner-migration.mdx +50 -0
- package/build/templates/overlays/planner-refactor.mdx +57 -0
- package/build/templates/overlays/researcher-library.mdx +59 -0
- package/build/templates/overlays/researcher-performance.mdx +68 -0
- package/build/templates/overlays/researcher-security.mdx +86 -0
- package/build/templates/overlays/tester-graphql.mdx +191 -0
- package/build/templates/overlays/tester-playwright.mdx +621 -0
- package/build/templates/overlays/tester-rest.mdx +101 -0
- package/build/templates/overlays/tester-suite.mdx +177 -0
- package/build/templates/super-coder.mdx +529 -0
- package/build/templates/super-planner.mdx +568 -0
- package/build/templates/super-researcher.mdx +406 -0
- package/build/templates/super-tester.mdx +243 -0
- package/build/tools/answer-question.d.ts +30 -0
- package/build/tools/answer-question.d.ts.map +1 -0
- package/build/tools/answer-question.js +108 -0
- package/build/tools/answer-question.js.map +1 -0
- package/build/tools/cancel-task.d.ts +44 -0
- package/build/tools/cancel-task.d.ts.map +1 -0
- package/build/tools/cancel-task.js +144 -0
- package/build/tools/cancel-task.js.map +1 -0
- package/build/tools/send-message.d.ts +39 -0
- package/build/tools/send-message.d.ts.map +1 -0
- package/build/tools/send-message.js +124 -0
- package/build/tools/send-message.js.map +1 -0
- package/build/tools/shared-spawn.d.ts +56 -0
- package/build/tools/shared-spawn.d.ts.map +1 -0
- package/build/tools/shared-spawn.js +114 -0
- package/build/tools/shared-spawn.js.map +1 -0
- package/build/tools/spawn-agent.d.ts +85 -0
- package/build/tools/spawn-agent.d.ts.map +1 -0
- package/build/tools/spawn-agent.js +133 -0
- package/build/tools/spawn-agent.js.map +1 -0
- package/build/tools/spawn-coder.d.ts +70 -0
- package/build/tools/spawn-coder.d.ts.map +1 -0
- package/build/tools/spawn-coder.js +71 -0
- package/build/tools/spawn-coder.js.map +1 -0
- package/build/tools/spawn-planner.d.ts +70 -0
- package/build/tools/spawn-planner.d.ts.map +1 -0
- package/build/tools/spawn-planner.js +71 -0
- package/build/tools/spawn-planner.js.map +1 -0
- package/build/tools/spawn-researcher.d.ts +70 -0
- package/build/tools/spawn-researcher.d.ts.map +1 -0
- package/build/tools/spawn-researcher.js +70 -0
- package/build/tools/spawn-researcher.js.map +1 -0
- package/build/tools/spawn-task.d.ts +74 -0
- package/build/tools/spawn-task.d.ts.map +1 -0
- package/build/tools/spawn-task.js +107 -0
- package/build/tools/spawn-task.js.map +1 -0
- package/build/tools/spawn-tester.d.ts +70 -0
- package/build/tools/spawn-tester.d.ts.map +1 -0
- package/build/tools/spawn-tester.js +69 -0
- package/build/tools/spawn-tester.js.map +1 -0
- package/build/types.d.ts +101 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +28 -0
- package/build/types.js.map +1 -0
- package/build/utils/brief-validator.d.ts +30 -0
- package/build/utils/brief-validator.d.ts.map +1 -0
- package/build/utils/brief-validator.js +254 -0
- package/build/utils/brief-validator.js.map +1 -0
- package/build/utils/format.d.ts +34 -0
- package/build/utils/format.d.ts.map +1 -0
- package/build/utils/format.js +55 -0
- package/build/utils/format.js.map +1 -0
- package/build/utils/sanitize.d.ts +240 -0
- package/build/utils/sanitize.d.ts.map +1 -0
- package/build/utils/sanitize.js +89 -0
- package/build/utils/sanitize.js.map +1 -0
- package/build/utils/task-id-generator.d.ts +10 -0
- package/build/utils/task-id-generator.d.ts.map +1 -0
- package/build/utils/task-id-generator.js +22 -0
- package/build/utils/task-id-generator.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
## TRIGGER.DEV CODING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are working in a codebase that uses **Trigger.dev v4** for background tasks. Follow these patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
### TASK DEFINITION
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { task, schemaTask, logger, metadata } from "@trigger.dev/sdk";
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
|
|
13
|
+
// Basic task
|
|
14
|
+
export const myTask = task({
|
|
15
|
+
id: "my-task", // globally unique, lowercase, hyphens OK
|
|
16
|
+
run: async (payload, { ctx }) => {
|
|
17
|
+
// ctx.run.id, ctx.task.id, ctx.attempt.number, ctx.environment.type
|
|
18
|
+
return result;
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// Schema-validated task (preferred)
|
|
23
|
+
export const validatedTask = schemaTask({
|
|
24
|
+
id: "validated-task",
|
|
25
|
+
schema: z.object({
|
|
26
|
+
userId: z.string().uuid(),
|
|
27
|
+
amount: z.number().positive(),
|
|
28
|
+
}),
|
|
29
|
+
run: async (payload) => {
|
|
30
|
+
// payload is validated and typed
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Critical rules:**
|
|
36
|
+
- Tasks MUST be exported and imported by the entry point (`trigger/index.ts`) to register
|
|
37
|
+
- Task IDs must be globally unique within the project
|
|
38
|
+
- Payloads must be JSON-serializable — no Dates (use ISO strings), no class instances, no circular refs
|
|
39
|
+
- Payload size limits: Free 64KB, Pro 3MB
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
### TRIGGERING PATTERNS
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// Fire-and-forget
|
|
47
|
+
const handle = await myTask.trigger({ userId: "123" }, {
|
|
48
|
+
idempotencyKey: "user-123-action", // prevent duplicate runs
|
|
49
|
+
tags: ["user-123"],
|
|
50
|
+
delay: "30s",
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// Trigger and wait for result
|
|
54
|
+
const result = await myTask.triggerAndWait({ userId: "123" });
|
|
55
|
+
if (result.ok) { /* result.output */ } else { /* result.error */ }
|
|
56
|
+
|
|
57
|
+
// Subtask orchestration
|
|
58
|
+
export const orchestrator = task({
|
|
59
|
+
id: "orchestrator",
|
|
60
|
+
run: async (payload) => {
|
|
61
|
+
const step1 = await subtaskA.triggerAndWait({ ... });
|
|
62
|
+
if (!step1.ok) throw new Error("Step 1 failed");
|
|
63
|
+
return await subtaskB.triggerAndWait({ input: step1.output });
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Parallel subtasks
|
|
68
|
+
const result = await batch.triggerByTaskAndWait([
|
|
69
|
+
{ task: taskA, payload: { ... } },
|
|
70
|
+
{ task: taskB, payload: { ... } },
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
// Batch (up to 500 per call, chunk larger sets)
|
|
74
|
+
const handles = await myTask.batchTrigger(
|
|
75
|
+
items.map(item => ({ payload: { item }, options: { idempotencyKey: `item-${item.id}` } }))
|
|
76
|
+
);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
### SCHEDULED TASKS
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { schedules } from "@trigger.dev/sdk";
|
|
85
|
+
|
|
86
|
+
export const dailyReport = schedules.task({
|
|
87
|
+
id: "daily-report",
|
|
88
|
+
cron: { pattern: "0 9 * * *", timezone: "America/New_York" },
|
|
89
|
+
run: async (payload) => {
|
|
90
|
+
// payload.timestamp, payload.lastTimestamp, payload.timezone
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Dynamic schedules (from backend)
|
|
95
|
+
await schedules.create({
|
|
96
|
+
task: "user-report",
|
|
97
|
+
cron: "0 9 * * 1",
|
|
98
|
+
externalId: "user-123",
|
|
99
|
+
deduplicationKey: "user-123-weekly",
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- Prevent overlapping: `queue: { concurrencyLimit: 1 }`
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
### LOGGING CONVENTIONS
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// Format: {operation}_{phase} in snake_case — ALWAYS
|
|
111
|
+
logger.info("document_process_started", {
|
|
112
|
+
correlation_id: `doc-${payload.id.slice(0, 8)}`,
|
|
113
|
+
request_id: payload.requestId,
|
|
114
|
+
run_id: ctx.run.id,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
logger.info("document_process_completed", {
|
|
118
|
+
correlation_id: correlationId,
|
|
119
|
+
processing_time_ms: Date.now() - startTime,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
logger.error("document_process_failed", {
|
|
123
|
+
correlation_id: correlationId,
|
|
124
|
+
error_type: error.name,
|
|
125
|
+
error_message: error.message,
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
- Message format: `{operation}_{phase}` (e.g., `order_process_started`, `payment_charge_failed`)
|
|
130
|
+
- Always snake_case for both message and data keys — never camelCase
|
|
131
|
+
- Lifecycle phases: `_started`, `_validating`, `_calling_{service}`, `_completed`, `_failed`
|
|
132
|
+
- Always include: `correlation_id`, `request_id`, `run_id`
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
### IDEMPOTENCY
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import { idempotencyKeys } from "@trigger.dev/sdk";
|
|
140
|
+
|
|
141
|
+
// Trigger-level (prevent duplicate runs)
|
|
142
|
+
await myTask.trigger({ orderId: "123" }, { idempotencyKey: "process-order-123" });
|
|
143
|
+
|
|
144
|
+
// Inside task — run-scoped (safe for retries)
|
|
145
|
+
const runKey = await idempotencyKeys.create(`charge-${orderId}`);
|
|
146
|
+
|
|
147
|
+
// Inside task — global (unique across different runs)
|
|
148
|
+
const globalKey = await idempotencyKeys.create(`order-${orderId}`, { scope: "global" });
|
|
149
|
+
|
|
150
|
+
// For long-term dedup (beyond 30-day TTL), use database-level checks
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Key patterns: `order-${orderId}`, `stripe-event-${event.id}`, `daily-report-${date}`
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### RETRIES & ERROR HANDLING
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
import { AbortTaskRunError } from "@trigger.dev/sdk";
|
|
161
|
+
|
|
162
|
+
export const apiTask = task({
|
|
163
|
+
id: "api-task",
|
|
164
|
+
retry: {
|
|
165
|
+
maxAttempts: 5,
|
|
166
|
+
factor: 2,
|
|
167
|
+
minTimeoutInMs: 2000,
|
|
168
|
+
maxTimeoutInMs: 30000,
|
|
169
|
+
randomize: true,
|
|
170
|
+
},
|
|
171
|
+
run: async (payload, { ctx }) => {
|
|
172
|
+
try {
|
|
173
|
+
return await apiCall(payload);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
// Don't retry validation/auth errors
|
|
176
|
+
if (error.status === 400 || error.status === 401 || error.status === 403) {
|
|
177
|
+
throw new AbortTaskRunError(`Unrecoverable: ${error.status}`);
|
|
178
|
+
}
|
|
179
|
+
throw error; // Retry on transient errors
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
| Use Case | Config |
|
|
186
|
+
|----------|--------|
|
|
187
|
+
| Network/transient | factor: 2, min: 1s, max: 30s, attempts: 5 |
|
|
188
|
+
| Rate limits | factor: 3, min: 5s, max: 120s, attempts: 3 |
|
|
189
|
+
| Database | factor: 1.5, min: 500ms, max: 5s, attempts: 3 |
|
|
190
|
+
| No retry | maxAttempts: 1 |
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### CONCURRENCY
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { queue } from "@trigger.dev/sdk";
|
|
198
|
+
|
|
199
|
+
// Per-task limit
|
|
200
|
+
export const limitedTask = task({
|
|
201
|
+
id: "limited-task",
|
|
202
|
+
queue: { concurrencyLimit: 10 },
|
|
203
|
+
run: async (payload) => { /* ... */ },
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Shared queue (multiple tasks share concurrency pool)
|
|
207
|
+
const apiQueue = queue({ name: "api-queue", concurrencyLimit: 10 });
|
|
208
|
+
|
|
209
|
+
export const taskA = task({ id: "task-a", queue: apiQueue, run: async () => {} });
|
|
210
|
+
export const taskB = task({ id: "task-b", queue: apiQueue, run: async () => {} });
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Limits: External API 5-20, Database 10-50, File processing 5-10, Singleton 1.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
### HOOKS & MIDDLEWARE
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
export const taskWithHooks = task({
|
|
221
|
+
id: "task-with-hooks",
|
|
222
|
+
onSuccess: async ({ output, ctx }) => { await notifySuccess(ctx.run.id, output); },
|
|
223
|
+
onFailure: async ({ error, ctx }) => { await notifyFailure(ctx.run.id, error); }, // after ALL retries
|
|
224
|
+
onWait: async () => { await db.disconnect(); },
|
|
225
|
+
onResume: async () => { await db.connect(); },
|
|
226
|
+
run: async (payload) => { /* ... */ },
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Global middleware (src/trigger/init.ts)
|
|
230
|
+
import { locals, tasks } from "@trigger.dev/sdk";
|
|
231
|
+
|
|
232
|
+
const DbLocal = locals.create<Database>("db");
|
|
233
|
+
export function getDb() { return locals.getOrThrow(DbLocal); }
|
|
234
|
+
|
|
235
|
+
tasks.middleware("db", async ({ next }) => {
|
|
236
|
+
const db = await Database.connect();
|
|
237
|
+
locals.set(DbLocal, db);
|
|
238
|
+
await next();
|
|
239
|
+
await db.disconnect();
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
### METADATA & STREAMING
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
// Progress updates (metadata limit: 256KB)
|
|
249
|
+
metadata.set({ status: "processing", progress: 0 });
|
|
250
|
+
metadata.set({ progress: Math.round(((i + 1) / total) * 100) });
|
|
251
|
+
|
|
252
|
+
// AI streaming
|
|
253
|
+
import { streamText } from "ai";
|
|
254
|
+
const result = streamText({ model: openai("gpt-4o"), prompt });
|
|
255
|
+
const fullStream = await metadata.stream("llm", result.fullStream);
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
For large data, store externally and put the URL in metadata.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
### CONFIGURATION (trigger.config.ts)
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { defineConfig } from "@trigger.dev/sdk";
|
|
266
|
+
|
|
267
|
+
export default defineConfig({
|
|
268
|
+
project: "<project-ref>",
|
|
269
|
+
dirs: ["./src/trigger"],
|
|
270
|
+
runtime: "node", // "node" | "node-22" | "bun"
|
|
271
|
+
logLevel: "info",
|
|
272
|
+
maxDuration: 300, // seconds
|
|
273
|
+
retries: {
|
|
274
|
+
enabledInDev: true,
|
|
275
|
+
default: { maxAttempts: 3, factor: 2, minTimeoutInMs: 1000, maxTimeoutInMs: 60000, randomize: true },
|
|
276
|
+
},
|
|
277
|
+
build: { external: ["sharp", "sqlite3"], autoDetectExternal: true },
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### ANTI-PATTERNS
|
|
284
|
+
|
|
285
|
+
| Anti-Pattern | Solution |
|
|
286
|
+
|---|---|
|
|
287
|
+
| Large payloads (data blobs) | Pass IDs/URLs, not data |
|
|
288
|
+
| Unexported tasks | Export + import in entry point |
|
|
289
|
+
| Non-serializable payloads (Dates, classes) | Use ISO strings, plain objects |
|
|
290
|
+
| Class instances across awaits | Rehydrate after every await (checkpoints) |
|
|
291
|
+
| No idempotency keys | Always use for important operations |
|
|
292
|
+
| Retrying non-transient errors | Use `AbortTaskRunError` for 400/401/403 |
|
|
293
|
+
| Overlapping scheduled tasks | Set `queue: { concurrencyLimit: 1 }` |
|
|
294
|
+
| camelCase log keys | Always snake_case |
|
|
295
|
+
| PII in logs | Log UUIDs, never emails/names |
|
|
296
|
+
| No run_id persistence | Always save `ctx.run.id` back to DB |
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
## TYPESCRIPT-SPECIFIC GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are working in a **TypeScript** codebase. Apply these principles with zero exceptions.
|
|
4
|
+
|
|
5
|
+
### Type Safety — NON-NEGOTIABLE
|
|
6
|
+
- ALWAYS use strict TypeScript (`strict: true` in tsconfig) — if the project has it disabled, note it but write strict code anyway
|
|
7
|
+
- **NEVER use `any`** — use `unknown` + type guards, or proper generic constraints
|
|
8
|
+
- Prefer `interface` over `type` for object shapes — interfaces are extendable and produce better error messages
|
|
9
|
+
- Use **discriminated unions** for state machines and variant types
|
|
10
|
+
- Use `as const` for literal types and enum-like objects
|
|
11
|
+
- **Explicit return types** on all exported functions — don't rely on inference for public API
|
|
12
|
+
- Use `readonly` arrays and objects where mutation is not needed
|
|
13
|
+
- Template literal types for string patterns (e.g., `type EventName = \`on${string}\``)
|
|
14
|
+
|
|
15
|
+
### Error Handling
|
|
16
|
+
- Use **typed error classes** that extend `Error` — never throw raw strings
|
|
17
|
+
- Use Result/Either pattern for expected failures (function returns success or typed error)
|
|
18
|
+
- Never `catch` and swallow — always handle, rethrow, or log with context
|
|
19
|
+
- Use `unknown` in catch blocks: `catch (err: unknown)`
|
|
20
|
+
|
|
21
|
+
### Imports & Module Structure
|
|
22
|
+
- **Named exports** over default exports (better refactoring, tree-shaking)
|
|
23
|
+
- Barrel exports (`index.ts`) for public APIs of modules
|
|
24
|
+
- Import grouping: `external packages` → `internal modules` → `type imports`
|
|
25
|
+
- Use `import type { ... }` for type-only imports (prevents runtime import)
|
|
26
|
+
- Never use `require()` in TypeScript
|
|
27
|
+
|
|
28
|
+
### Code Patterns
|
|
29
|
+
- Prefer **composition over inheritance** — use interfaces + factory functions
|
|
30
|
+
- Use `Map`/`Set` over plain objects for dynamic keys
|
|
31
|
+
- Prefer `for...of` over `forEach` for readability and `break`/`continue` support
|
|
32
|
+
- Use optional chaining (`?.`) and nullish coalescing (`??`) — avoid `&&` chains for null checks
|
|
33
|
+
- Use `satisfies` operator for type checking without widening
|
|
34
|
+
|
|
35
|
+
### Naming Conventions
|
|
36
|
+
- `PascalCase` for types, interfaces, classes, enums
|
|
37
|
+
- `camelCase` for variables, functions, methods
|
|
38
|
+
- `UPPER_SNAKE_CASE` for constants
|
|
39
|
+
- Prefix interfaces with context, not `I` — `UserService` not `IUserService`
|
|
40
|
+
- Boolean variables: `is*`, `has*`, `can*`, `should*`
|
|
41
|
+
|
|
42
|
+
### Testing Considerations
|
|
43
|
+
- Write code that is **easily testable** — pure functions, dependency injection, no hidden globals
|
|
44
|
+
- Export internal functions for testing only via `/** @internal */` JSDoc tag
|
|
45
|
+
- Prefer deterministic code — avoid `Date.now()` directly, accept timestamps as params
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
## VUE-SPECIFIC GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are working in a **Vue** codebase. Apply these principles with zero exceptions.
|
|
4
|
+
|
|
5
|
+
### Composition API — The Default
|
|
6
|
+
- Use **Composition API** with `<script setup>` — not Options API, unless the project explicitly uses it
|
|
7
|
+
- `<script setup>` is the recommended syntax — all top-level bindings are automatically exposed to the template
|
|
8
|
+
- Keep `<script setup>` organized: imports → props/emits → reactive state → computed → watchers → functions → lifecycle
|
|
9
|
+
|
|
10
|
+
### Reactivity — ref/reactive
|
|
11
|
+
- Use `ref()` for primitives and values you might reassign: `const count = ref(0)`
|
|
12
|
+
- Use `reactive()` for objects/collections that you mutate: `const form = reactive({ name: '', email: '' })`
|
|
13
|
+
- Access `ref` values with `.value` in script, automatic unwrapping in templates
|
|
14
|
+
- **Never destructure reactive objects** — it breaks reactivity. Use `toRefs()` if needed
|
|
15
|
+
- Use `shallowRef()` / `shallowReactive()` for large objects where deep reactivity is wasteful
|
|
16
|
+
|
|
17
|
+
### Computed & Watch
|
|
18
|
+
- Use `computed()` for derived state — automatically cached and dependency-tracked
|
|
19
|
+
- Use `watch()` for side effects when reactive data changes — API calls, logging
|
|
20
|
+
- Use `watchEffect()` when you want automatic dependency tracking (no explicit source)
|
|
21
|
+
- Avoid watchers when computed will do — computed is simpler and more performant
|
|
22
|
+
- Use `{ immediate: true }` when the watcher should run on initialization
|
|
23
|
+
|
|
24
|
+
### Composables — Reusable Logic
|
|
25
|
+
- Extract reusable stateful logic into composables: `useAuth()`, `useFetch()`, `useLocalStorage()`
|
|
26
|
+
- Composable naming: always start with `use`
|
|
27
|
+
- Composables go in `composables/` directory
|
|
28
|
+
- Composables can use all Composition API features: ref, computed, watch, lifecycle hooks
|
|
29
|
+
- Return reactive state and methods from composables — let the consumer decide how to use them
|
|
30
|
+
|
|
31
|
+
### Pinia — State Management
|
|
32
|
+
- Use **Pinia** for global state — not Vuex (Pinia is the official recommendation)
|
|
33
|
+
- Use `defineStore()` with Setup Store syntax (Composition API style) — matches component patterns
|
|
34
|
+
- Keep stores focused — one store per domain concern
|
|
35
|
+
- Use `storeToRefs()` when destructuring store state in components — preserves reactivity
|
|
36
|
+
- Actions can be async — use them for API calls and complex mutations
|
|
37
|
+
|
|
38
|
+
### Single-File Component Conventions
|
|
39
|
+
- Order: `<script setup>` → `<template>` → `<style scoped>`
|
|
40
|
+
- Use `scoped` styles by default — prevents CSS leaking
|
|
41
|
+
- Use CSS `v-bind()` for dynamic styles based on reactive data
|
|
42
|
+
- Keep templates readable — extract complex logic into computed properties or composables
|
|
43
|
+
- Use `<component :is="...">` for dynamic components
|
|
44
|
+
|
|
45
|
+
### Props & Events
|
|
46
|
+
- Define props with `defineProps<{ name: string; count?: number }>()` — TypeScript-typed
|
|
47
|
+
- Define emits with `defineEmits<{ (e: 'update', value: string): void }>()` — typed events
|
|
48
|
+
- Use `v-model` with `defineModel()` (Vue 3.4+) for two-way binding
|
|
49
|
+
- Props are readonly — never mutate props directly. Emit an event to request parent changes
|
|
50
|
+
|
|
51
|
+
### Naming Conventions
|
|
52
|
+
- `PascalCase` for components in script: `import UserCard from './UserCard.vue'`
|
|
53
|
+
- `PascalCase` or `kebab-case` for components in templates (follow project convention)
|
|
54
|
+
- `camelCase` for composables, functions, variables
|
|
55
|
+
- Props: `camelCase` in script, `kebab-case` in templates: `prop: userName` → `<Comp :user-name="...">`
|
|
56
|
+
- Events: `camelCase` with `defineEmits`: `update:modelValue`, `itemClicked`
|
|
57
|
+
|
|
58
|
+
### Testing Considerations
|
|
59
|
+
- Write composables as pure functions when possible — testable without component mounting
|
|
60
|
+
- Use `@vue/test-utils` `mount()` / `shallowMount()` for component tests
|
|
61
|
+
- Use Pinia test helpers: `createTestingPinia()` with `initialState`
|
|
62
|
+
- Prefer testing behavior over implementation — test what the user sees, not internal state
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
## ARCHITECTURE PLANNING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are planning an **architectural change**. This affects system boundaries, component relationships, and data flow. Get it right — architecture mistakes are expensive to fix.
|
|
4
|
+
|
|
5
|
+
### Discovery Phase — MANDATORY
|
|
6
|
+
- **Map current component boundaries:** What modules/services exist? What are their responsibilities?
|
|
7
|
+
- **Identify integration points:** How do components communicate? (function calls, HTTP, events, shared DB, message queue)
|
|
8
|
+
- **Trace data flow:** Follow data from entry point to storage and back — document the full path
|
|
9
|
+
- **Find coupling:** Where do components know too much about each other's internals?
|
|
10
|
+
- **Identify the pain point:** What specific architectural problem are you solving? (scaling bottleneck, tangled dependencies, deployment coupling, etc.)
|
|
11
|
+
|
|
12
|
+
### Design Principles
|
|
13
|
+
- **Separation of concerns:** Each component has ONE reason to change
|
|
14
|
+
- **Dependency direction:** Dependencies point inward (domain doesn't depend on infrastructure)
|
|
15
|
+
- **Interface boundaries:** Define explicit contracts between components — not implicit coupling
|
|
16
|
+
- **Minimize shared state:** Shared mutable state is the root of most architecture problems
|
|
17
|
+
- **Design for the failure case:** What happens when a component is slow, down, or returns errors?
|
|
18
|
+
|
|
19
|
+
### Task Structure — The Architecture Sequence
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
1. DEFINE INTERFACES / CONTRACTS
|
|
23
|
+
└─ Create the new interfaces, types, protocols that define component boundaries
|
|
24
|
+
└─ These are the contracts that consumers and implementors agree on
|
|
25
|
+
└─ No behavior change yet — just contracts
|
|
26
|
+
|
|
27
|
+
2. IMPLEMENT CORE DOMAIN LOGIC
|
|
28
|
+
└─ Build the core business logic behind the new interfaces
|
|
29
|
+
└─ Pure functions and domain types — no infrastructure concerns
|
|
30
|
+
└─ Testable in isolation
|
|
31
|
+
|
|
32
|
+
3. BUILD ADAPTERS
|
|
33
|
+
└─ Create adapters that connect domain logic to infrastructure (DB, HTTP, file system)
|
|
34
|
+
└─ Each adapter implements one interface
|
|
35
|
+
└─ Adapters are independently replaceable
|
|
36
|
+
|
|
37
|
+
4. WIRE ORCHESTRATION
|
|
38
|
+
└─ Connect components through the defined interfaces
|
|
39
|
+
└─ Dependency injection or factory pattern for assembly
|
|
40
|
+
└─ Configuration and startup sequence
|
|
41
|
+
|
|
42
|
+
5. INTEGRATION VERIFICATION
|
|
43
|
+
└─ End-to-end verification that all components work together
|
|
44
|
+
└─ Performance baseline to compare with previous architecture
|
|
45
|
+
└─ Migration plan for any data or state that needs to move
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Decision Documentation
|
|
49
|
+
For each significant architectural decision, document using ADR (Architecture Decision Record) format:
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
## ADR-[N]: [Title]
|
|
53
|
+
|
|
54
|
+
**Status:** Proposed
|
|
55
|
+
**Context:** [What problem are we facing?]
|
|
56
|
+
**Decision:** [What we decided]
|
|
57
|
+
**Consequences:**
|
|
58
|
+
- [Positive consequence]
|
|
59
|
+
- [Negative consequence / trade-off]
|
|
60
|
+
**Reversibility:** [Easy / Hard / Irreversible] — [explanation]
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Classify decisions:**
|
|
64
|
+
- **Reversible (two-way door):** Decide quickly, adjust later. Example: choosing a serialization format
|
|
65
|
+
- **Irreversible (one-way door):** Think deeply, get input. Example: splitting a monolith, choosing a message broker
|
|
66
|
+
|
|
67
|
+
### Risk Assessment — CRITICAL
|
|
68
|
+
- **Migration complexity:** Can old and new architecture coexist during transition? (Strangler fig pattern)
|
|
69
|
+
- **Data migration:** Does data need to move between systems/schemas? Plan this separately
|
|
70
|
+
- **Performance regression:** Will the new architecture introduce latency (extra network hops, serialization)?
|
|
71
|
+
- **Operational complexity:** More components = more things to deploy, monitor, debug
|
|
72
|
+
- **Team impact:** Does the team understand the new architecture? Training needed?
|
|
73
|
+
|
|
74
|
+
### Task Design
|
|
75
|
+
- Each task: **one component or one boundary change**, independently deployable
|
|
76
|
+
- Success criteria include: "Component X communicates with Y only through interface Z"
|
|
77
|
+
- Never combine infrastructure changes with domain logic changes in one task
|
|
78
|
+
- Include rollback strategy for each architectural change
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## BUG FIX PLANNING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are planning a **bug fix**. Root cause analysis is paramount — never plan a fix for symptoms.
|
|
4
|
+
|
|
5
|
+
### Root Cause Analysis — DO THIS FIRST
|
|
6
|
+
- **Reproduce the bug path:** Trace from user input → code execution path → failure point
|
|
7
|
+
- **Identify the ROOT cause**, not just where the error appears — the error location and the bug location are often different
|
|
8
|
+
- **Check:** Is this a single bug or a pattern? Search the codebase for similar code that might have the same issue
|
|
9
|
+
- **Timeline:** When was this introduced? Was there a recent change that caused it? (`git log` the affected files)
|
|
10
|
+
- **Scope:** Who is affected? All users? Specific conditions? Specific environments?
|
|
11
|
+
|
|
12
|
+
### Fix Strategy — Minimal and Upstream
|
|
13
|
+
- **Prefer minimal upstream fix** over downstream workaround — fix where the data goes wrong, not where the error surfaces
|
|
14
|
+
- **Single-line fix if sufficient** — don't refactor adjacent code just because you're in the file
|
|
15
|
+
- **Consider regressions:** Will this fix break anything else? Check all callers of the affected function
|
|
16
|
+
- **Verify the fix concept** before planning implementation — does the logic actually solve the root cause?
|
|
17
|
+
|
|
18
|
+
### Mandatory Task Structure
|
|
19
|
+
Every bug fix plan MUST include these tasks:
|
|
20
|
+
|
|
21
|
+
1. **Root cause documentation** — Write a clear explanation of what went wrong and why
|
|
22
|
+
2. **The fix itself** — Minimal code change that addresses the root cause
|
|
23
|
+
3. **Regression test** — A test that fails before the fix and passes after
|
|
24
|
+
4. **Pattern check** — Search for the same bug pattern elsewhere in the codebase and fix if found
|
|
25
|
+
|
|
26
|
+
### Task Design
|
|
27
|
+
- Each task: **one file change**, clear before/after behavior
|
|
28
|
+
- Success criteria: "Before fix: [behavior]. After fix: [behavior]"
|
|
29
|
+
- Include the **exact error message, stack trace, or reproduction steps** in the Builder brief
|
|
30
|
+
- Reference the **specific line numbers** where the bug occurs
|
|
31
|
+
|
|
32
|
+
### Risk Assessment
|
|
33
|
+
- **Regression risk:** What could this fix break? List explicitly
|
|
34
|
+
- **Data impact:** Has bad data been written? Is cleanup needed?
|
|
35
|
+
- **Deployment urgency:** Is this blocking production? Hotfix or normal release?
|
|
36
|
+
- **Rollback plan:** If the fix causes new issues, what's the rollback?
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
## FEATURE PLANNING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are planning a **new feature**. This requires comprehensive discovery and careful task design.
|
|
4
|
+
|
|
5
|
+
### Discovery Phase — MANDATORY
|
|
6
|
+
- **Map ALL touchpoints:** UI components, API endpoints, database tables, background services, third-party integrations
|
|
7
|
+
- **Identify affected user flows** end-to-end — trace from user action to database and back
|
|
8
|
+
- **Find existing patterns** for similar features in the codebase — the new feature should follow established conventions
|
|
9
|
+
- **Audit dependencies:** What libraries/services does this feature need? Are they already available?
|
|
10
|
+
- **Check for feature flags:** Does the project use feature flags? Should this be behind one?
|
|
11
|
+
|
|
12
|
+
### Task Design — Sequence Matters
|
|
13
|
+
1. **Data model first** — database migrations, schema changes, type definitions
|
|
14
|
+
2. **Service/business logic layer** — core functionality without UI
|
|
15
|
+
3. **API layer** — endpoints, request/response schemas, validation
|
|
16
|
+
4. **UI integration** — components, state management, routing
|
|
17
|
+
5. **Integration tests** — end-to-end verification
|
|
18
|
+
|
|
19
|
+
Each task MUST have:
|
|
20
|
+
- **Single deliverable** — one file or one behavior change
|
|
21
|
+
- **Clear success criteria** — objective, testable conditions
|
|
22
|
+
- **File paths** — exact paths the Builder needs to create/modify
|
|
23
|
+
- **Patterns to follow** — reference existing code that does something similar
|
|
24
|
+
|
|
25
|
+
### Risk Assessment
|
|
26
|
+
- **New dependencies:** Do we need new packages? Version compatibility?
|
|
27
|
+
- **Database migrations:** Reversible? Data backfill needed? Downtime?
|
|
28
|
+
- **Backwards compatibility:** Does this break existing API consumers?
|
|
29
|
+
- **Performance:** How does this scale? N+1 queries? Large payloads?
|
|
30
|
+
- **Security:** New attack surface? Auth/authz implications?
|
|
31
|
+
|
|
32
|
+
### Handoff Quality Checklist
|
|
33
|
+
Before marking planning complete, verify:
|
|
34
|
+
- [ ] Builder brief has EXACT file paths for every task
|
|
35
|
+
- [ ] Every task references existing code patterns to follow
|
|
36
|
+
- [ ] Success criteria are testable (not "works well" but "returns 200 with valid JWT")
|
|
37
|
+
- [ ] Tester checklist covers: happy path, error cases, edge cases, visual checks
|
|
38
|
+
- [ ] Dependencies between tasks are explicit and wave-grouped
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
## MIGRATION PLANNING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are planning a **migration** (API version, database schema, library upgrade, framework change). Safety and reversibility are paramount.
|
|
4
|
+
|
|
5
|
+
### Assessment Phase — MANDATORY
|
|
6
|
+
- **Current state:** Document exactly what exists today — versions, schemas, dependencies, consumers
|
|
7
|
+
- **Target state:** Document exactly what "done" looks like — new versions, new schemas, new APIs
|
|
8
|
+
- **Scope:** List ALL affected files, services, database tables, API consumers, configuration files
|
|
9
|
+
- **Breaking changes:** Explicitly list every breaking change between current and target state
|
|
10
|
+
|
|
11
|
+
### Migration Strategy
|
|
12
|
+
- **Incremental migration (strangler fig) PREFERRED** — replace piece by piece, not big-bang
|
|
13
|
+
- **Coexistence period:** Can old and new run simultaneously during transition? Design for this
|
|
14
|
+
- **Rollback plan is MANDATORY** — every migration task must be individually reversible
|
|
15
|
+
- **Feature flags:** Use feature flags to control rollout if available in the project
|
|
16
|
+
- **Data migration:** If database changes are involved, plan the data migration separately from schema migration
|
|
17
|
+
|
|
18
|
+
### Phase Structure — Every Migration Plan Must Have These
|
|
19
|
+
|
|
20
|
+
**Phase 1: Preparation (no behavior change)**
|
|
21
|
+
- Add compatibility layers, adapters, new schemas alongside old
|
|
22
|
+
- Add deprecation warnings to old code paths
|
|
23
|
+
- Create migration utilities/scripts
|
|
24
|
+
- All existing tests must still pass
|
|
25
|
+
|
|
26
|
+
**Phase 2: Migration (gradual switchover)**
|
|
27
|
+
- Switch consumers one at a time to new code paths
|
|
28
|
+
- Run old and new in parallel where possible
|
|
29
|
+
- Monitor for errors/regressions at each step
|
|
30
|
+
- Each task independently deployable and rollback-able
|
|
31
|
+
|
|
32
|
+
**Phase 3: Cleanup (remove old code)**
|
|
33
|
+
- Remove deprecated code paths
|
|
34
|
+
- Remove compatibility layers
|
|
35
|
+
- Remove old schemas/migrations
|
|
36
|
+
- Update documentation
|
|
37
|
+
- This phase should be a SEPARATE plan — don't mix cleanup with migration
|
|
38
|
+
|
|
39
|
+
### Risk Assessment — CRITICAL
|
|
40
|
+
- **Data loss scenarios:** Can any migration step lose data? How is this prevented?
|
|
41
|
+
- **Downtime requirements:** Does any step require downtime? How long? Can it be zero-downtime?
|
|
42
|
+
- **Consumer impact:** Who depends on the old API/schema? Have they been notified?
|
|
43
|
+
- **Performance regression:** Does the new version perform the same or better? Benchmark
|
|
44
|
+
- **Rollback testing:** Has the rollback procedure been verified?
|
|
45
|
+
|
|
46
|
+
### Task Design
|
|
47
|
+
- Each task: **one migration step**, independently deployable, independently reversible
|
|
48
|
+
- Success criteria include: "Rollback: [exact steps to undo this task]"
|
|
49
|
+
- Never combine schema migration with data migration in one task
|
|
50
|
+
- Never combine behavior changes with cleanup in one task
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
## REFACTORING PLANNING GUIDELINES
|
|
2
|
+
|
|
3
|
+
You are planning a **refactoring**. The codebase must work correctly at every step — never break it in the middle.
|
|
4
|
+
|
|
5
|
+
### Assessment Phase — MANDATORY
|
|
6
|
+
- **Identify the code smell or structural problem** — name it precisely (duplication, God class, feature envy, shotgun surgery, etc.)
|
|
7
|
+
- **Map ALL usages** of the code you want to change — use `warpgrep_codebase_search` exhaustively
|
|
8
|
+
- **Quantify blast radius:** How many files, functions, and callers are affected?
|
|
9
|
+
- **Check for existing tests** — if tests cover the code, they're your safety net. If not, characterization tests come first
|
|
10
|
+
- **Understand the current behavior completely** before planning any changes — refactoring changes structure, not behavior
|
|
11
|
+
|
|
12
|
+
### Strategy — Strangler Fig Pattern
|
|
13
|
+
- **Each task must leave the codebase in a working state** — never a "break it then fix it" sequence
|
|
14
|
+
- **New code alongside old:** Introduce the new pattern/structure first, THEN migrate consumers, THEN remove old code
|
|
15
|
+
- **Tests pass after every task** — if a task breaks tests, the task is too big or the approach is wrong
|
|
16
|
+
- **Incremental over big-bang** — 5 small safe steps beat 1 large risky step
|
|
17
|
+
|
|
18
|
+
### Task Structure — The Refactoring Sequence
|
|
19
|
+
|
|
20
|
+
Every refactoring plan MUST follow this sequence:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
1. ADD CHARACTERIZATION TESTS (if missing)
|
|
24
|
+
└─ Write tests that document current behavior
|
|
25
|
+
└─ These tests MUST pass before AND after every subsequent task
|
|
26
|
+
|
|
27
|
+
2. INTRODUCE NEW PATTERN ALONGSIDE OLD
|
|
28
|
+
└─ Create the new abstraction/structure/function
|
|
29
|
+
└─ Old code still works unchanged
|
|
30
|
+
└─ Tests still pass
|
|
31
|
+
|
|
32
|
+
3. MIGRATE CONSUMERS ONE-BY-ONE
|
|
33
|
+
└─ Each task migrates ONE consumer from old → new
|
|
34
|
+
└─ Tests pass after each migration
|
|
35
|
+
└─ Old and new coexist during this phase
|
|
36
|
+
|
|
37
|
+
4. REMOVE OLD CODE
|
|
38
|
+
└─ Only after ALL consumers migrated
|
|
39
|
+
└─ Verify no remaining references
|
|
40
|
+
└─ Tests still pass
|
|
41
|
+
|
|
42
|
+
5. VERIFY ALL TESTS PASS
|
|
43
|
+
└─ Full test suite run
|
|
44
|
+
└─ Manual verification of key flows if applicable
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Risk Assessment
|
|
48
|
+
- **Behavioral change risk:** Refactoring should NOT change behavior. If it does, that's a feature change disguised as refactoring — split it
|
|
49
|
+
- **Merge conflict risk:** Is anyone else working on these files? Coordinate or plan for conflict resolution
|
|
50
|
+
- **Rollback plan per task:** Each task should be individually revertable with `git revert`
|
|
51
|
+
- **Integration risk:** Does this refactoring affect API contracts, database queries, or external service calls?
|
|
52
|
+
|
|
53
|
+
### Task Design
|
|
54
|
+
- Each task: **one file or one logical change**, tests pass after
|
|
55
|
+
- Success criteria: "Before: [code structure]. After: [code structure]. Behavior: unchanged"
|
|
56
|
+
- Include the **exact code pattern** being replaced and the new pattern — Builder should not have to figure out the transformation
|
|
57
|
+
- Reference the **specific functions/classes** being refactored with file paths and line ranges
|