@dv.nghiem/flowdeck 0.2.3 → 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 +24 -41
- package/dist/hooks/memory-hook.d.ts +21 -0
- package/dist/hooks/memory-hook.d.ts.map +1 -0
- package/dist/hooks/orchestrator-guard-hook.d.ts +2 -1
- package/dist/hooks/orchestrator-guard-hook.d.ts.map +1 -1
- package/dist/hooks/todo-hook.d.ts +1 -7
- package/dist/hooks/todo-hook.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +649 -310
- package/dist/services/memory-store.d.ts +40 -0
- package/dist/services/memory-store.d.ts.map +1 -0
- package/dist/services/telemetry.d.ts +1 -1
- package/dist/services/telemetry.d.ts.map +1 -1
- package/dist/tools/memory-search.d.ts +3 -0
- package/dist/tools/memory-search.d.ts.map +1 -0
- package/docs/commands/fd-doctor.md +21 -0
- package/docs/commands/fd-quick.md +33 -0
- package/docs/commands/fd-reflect.md +23 -0
- package/docs/commands/fd-status.md +31 -0
- package/docs/commands/fd-translate-intent.md +17 -0
- package/docs/commands.md +209 -271
- package/docs/configuration.md +2 -1
- package/docs/index.md +22 -28
- package/docs/memory.md +69 -0
- package/docs/quick-start.md +1 -1
- package/docs/workflows.md +72 -320
- package/package.json +1 -2
- package/src/commands/fd-deploy-check.md +189 -34
- package/src/commands/fd-discuss.md +44 -6
- package/src/commands/fd-fix-bug.md +47 -20
- package/src/commands/fd-map-codebase.md +66 -18
- package/src/commands/fd-multi-repo.md +130 -6
- package/src/commands/fd-new-feature.md +164 -21
- package/src/commands/fd-new-project.md +14 -1
- package/src/commands/fd-plan.md +66 -44
- package/src/commands/fd-quick.md +60 -0
- package/src/commands/fd-reflect.md +41 -2
- package/src/commands/fd-status.md +84 -0
- package/src/commands/fd-write-docs.md +55 -23
- package/src/rules/README.md +8 -7
- package/src/skills/agent-harness-construction/SKILL.md +227 -0
- package/src/skills/api-design/SKILL.md +5 -0
- package/src/skills/backend-patterns/SKILL.md +105 -0
- package/src/skills/clean-architecture/SKILL.md +85 -0
- package/src/skills/cqrs/SKILL.md +230 -0
- package/src/skills/ddd-architecture/SKILL.md +104 -0
- package/src/skills/django-patterns/SKILL.md +304 -0
- package/src/skills/django-tdd/SKILL.md +297 -0
- package/src/skills/event-driven-architecture/SKILL.md +152 -0
- package/src/skills/frontend-pattern/SKILL.md +159 -0
- package/src/skills/hexagonal-architecture/SKILL.md +80 -0
- package/src/skills/layered-architecture/SKILL.md +64 -0
- package/src/skills/postgres-patterns/SKILL.md +74 -0
- package/src/skills/python-patterns/SKILL.md +5 -0
- package/src/skills/saga-architecture/SKILL.md +113 -0
- package/dist/tools/run-parallel.d.ts +0 -4
- package/dist/tools/run-parallel.d.ts.map +0 -1
- package/docs/command-migration.md +0 -175
- package/docs/commands/fd-analyze-change.md +0 -107
- package/docs/commands/fd-dashboard.md +0 -11
- package/docs/commands/fd-evaluate-risk.md +0 -134
- package/docs/commands/fd-guarded-edit.md +0 -105
- package/docs/commands/fd-progress.md +0 -11
- package/docs/commands/fd-review-code.md +0 -29
- package/docs/commands/fd-roadmap.md +0 -10
- package/docs/commands/fd-settings.md +0 -10
- package/docs/parallel-execution.md +0 -227
- package/src/commands/fd-analyze-change.md +0 -57
- package/src/commands/fd-approve.md +0 -64
- package/src/commands/fd-blast-radius.md +0 -49
- package/src/commands/fd-dashboard.md +0 -57
- package/src/commands/fd-evaluate-risk.md +0 -62
- package/src/commands/fd-guarded-edit.md +0 -69
- package/src/commands/fd-impact-radar.md +0 -51
- package/src/commands/fd-learn.md +0 -36
- package/src/commands/fd-progress.md +0 -50
- package/src/commands/fd-regression-predict.md +0 -57
- package/src/commands/fd-review-code.md +0 -62
- package/src/commands/fd-review-route.md +0 -54
- package/src/commands/fd-roadmap.md +0 -46
- package/src/commands/fd-settings.md +0 -57
- package/src/commands/fd-test-gap.md +0 -54
- package/src/commands/fd-volatility-map.md +0 -64
- package/src/commands/fd-workspace-status.md +0 -34
- package/src/skills/parallel-execute/SKILL.md +0 -92
- package/src/workflows/debug-flow.md +0 -119
- package/src/workflows/deploy-check-flow.md +0 -98
- package/src/workflows/discuss-flow.md +0 -97
- package/src/workflows/execute-flow.md +0 -233
- package/src/workflows/execute-phase.md +0 -145
- package/src/workflows/fix-bug-flow.md +0 -210
- package/src/workflows/map-codebase-flow.md +0 -92
- package/src/workflows/multi-repo-flow.md +0 -226
- package/src/workflows/parallel-execution-flow.md +0 -236
- package/src/workflows/plan-flow.md +0 -126
- package/src/workflows/plan-phase.md +0 -101
- package/src/workflows/refactor-flow.md +0 -122
- package/src/workflows/review-code-flow.md +0 -105
- package/src/workflows/spec-driven-flow.md +0 -43
- package/src/workflows/write-docs-flow.md +0 -95
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: View project status — combined status, roadmap, workspace overview, and progress
|
|
3
|
+
argument-hint: [--roadmap | --workspace | --phase=N]
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Status
|
|
7
|
+
|
|
8
|
+
View project status combining progress, roadmap, and workspace overview.
|
|
9
|
+
|
|
10
|
+
**Input:** $ARGUMENTS — optional flags
|
|
11
|
+
|
|
12
|
+
## Modes
|
|
13
|
+
|
|
14
|
+
### Default (no flags)
|
|
15
|
+
|
|
16
|
+
Read `.planning/STATE.md` and display combined status:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
════════════════════════════════════════════════════════════
|
|
20
|
+
Phase: <N> | Status: <status> | Updated: <timestamp>
|
|
21
|
+
────────────────────────────────────────────────────────────
|
|
22
|
+
Plan: <X> steps (<Y> complete)
|
|
23
|
+
Plan confirmed: <yes/no>
|
|
24
|
+
════════════════════════════════════════════════════════════
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Roadmap (`--roadmap`)
|
|
28
|
+
|
|
29
|
+
Display project roadmap with phase statuses:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
═══════════════════════════════════════
|
|
33
|
+
PROJECT ROADMAP
|
|
34
|
+
═══════════════════════════════════════
|
|
35
|
+
✅ Phase 1: <name> — completed
|
|
36
|
+
🔄 Phase 2: <name> — in progress ← current
|
|
37
|
+
⏳ Phase 3: <name> — planned
|
|
38
|
+
═══════════════════════════════════════
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Read from `.planning/ROADMAP.md` and `.planning/STATE.md`.
|
|
42
|
+
|
|
43
|
+
### Workspace (`--workspace`)
|
|
44
|
+
|
|
45
|
+
Display overview of all registered repositories:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
════════════════════════════════════════════════════
|
|
49
|
+
WORKSPACE OVERVIEW
|
|
50
|
+
════════════════════════════════════════════════════
|
|
51
|
+
frontend — Phase 2 | in_progress | Plan: ✅ | Updated: <time>
|
|
52
|
+
backend — Phase 3 | completed | Plan: ✅ | Updated: <time>
|
|
53
|
+
shared — Phase 1 | planned | Plan: ❌ | Updated: <time>
|
|
54
|
+
────────────────────────────────────────────────────
|
|
55
|
+
Total: 3 repos | 1 in progress | 1 completed | 1 planned
|
|
56
|
+
════════════════════════════════════════════════════
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Read from `.planning/config.json` for repo list, each repo's STATE.md for phase/status.
|
|
60
|
+
|
|
61
|
+
### Phase Detail (`--phase=N`)
|
|
62
|
+
|
|
63
|
+
Show detailed progress for a specific phase:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
════════════════════════════════════════════════════════════
|
|
67
|
+
PHASE <N> DETAIL
|
|
68
|
+
════════════════════════════════════════════════════════════
|
|
69
|
+
Status: <status>
|
|
70
|
+
Plan file: <path>
|
|
71
|
+
Plan confirmed: <yes/no>
|
|
72
|
+
|
|
73
|
+
Steps:
|
|
74
|
+
✅ Step 1: <name> — completed
|
|
75
|
+
🔄 Step 2: <name> — in progress
|
|
76
|
+
⬜ Step 3: <name> — pending
|
|
77
|
+
⬜ Step 4: <name> — pending
|
|
78
|
+
════════════════════════════════════════════════════════════
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Error Handling
|
|
82
|
+
|
|
83
|
+
- If `.planning/STATE.md` not found: "No active project. Run /fd-new-project first."
|
|
84
|
+
- If `--phase` requested but phase directory doesn't exist: "Phase N not found."
|
|
@@ -5,46 +5,78 @@ argument-hint: [--scope=path | --format=api,guide,readme]
|
|
|
5
5
|
|
|
6
6
|
# Write Docs
|
|
7
7
|
|
|
8
|
-
Generate documentation
|
|
8
|
+
Generate accurate, up-to-date documentation from the codebase.
|
|
9
9
|
|
|
10
10
|
**Input:** $ARGUMENTS — optional `--scope=<path>` and `--format=<type>`
|
|
11
11
|
|
|
12
12
|
Supported formats: `api` (API reference), `guide` (usage guide), `readme` (README)
|
|
13
13
|
Default: all formats
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## Process
|
|
16
16
|
|
|
17
|
-
###
|
|
17
|
+
### Step 1: Explore APIs
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
-
|
|
19
|
+
Spawn `@mapper` to:
|
|
20
|
+
- Find all exported functions, classes, and types
|
|
21
|
+
- Identify public API entry points
|
|
22
|
+
- Map key workflows and integration points
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
```bash
|
|
25
|
+
# Find exports
|
|
26
|
+
grep -rn "export " src/ --include="*.ts"
|
|
27
|
+
# Find public interfaces
|
|
28
|
+
grep -rn "export interface\|export type\|export class" src/ --include="*.ts"
|
|
29
|
+
```
|
|
23
30
|
|
|
24
|
-
|
|
25
|
-
- API docs: function signatures, parameters, return types, examples
|
|
26
|
-
- Guides: usage examples, step-by-step instructions
|
|
27
|
-
- README: project overview, install, quickstart, API summary
|
|
31
|
+
### Step 2: Draft Documentation
|
|
28
32
|
|
|
29
|
-
|
|
33
|
+
Spawn `@writer` to produce:
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
**API Reference**
|
|
36
|
+
```markdown
|
|
37
|
+
## functionName(param: Type): ReturnType
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
Description of what the function does.
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
**Parameters:**
|
|
42
|
+
- `param` (Type) — description
|
|
38
43
|
|
|
39
|
-
|
|
44
|
+
**Returns:** description
|
|
40
45
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
**Example:**
|
|
47
|
+
\`\`\`typescript
|
|
48
|
+
const result = functionName(value);
|
|
49
|
+
\`\`\`
|
|
50
|
+
```
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
**Usage Guide**
|
|
53
|
+
- Step-by-step workflow with examples
|
|
54
|
+
- Common patterns and best practices
|
|
55
|
+
- Configuration options
|
|
47
56
|
|
|
48
|
-
|
|
57
|
+
**Troubleshooting**
|
|
58
|
+
- Common errors and their solutions
|
|
59
|
+
|
|
60
|
+
### Step 3: Review for Accuracy
|
|
61
|
+
|
|
62
|
+
Spawn `@reviewer` to verify:
|
|
63
|
+
- Every documented function/method actually exists
|
|
64
|
+
- Parameter types match the actual signatures
|
|
65
|
+
- Examples are syntactically correct
|
|
66
|
+
- No outdated API references
|
|
67
|
+
|
|
68
|
+
### Step 4: Finalize
|
|
69
|
+
|
|
70
|
+
Writer incorporates feedback and writes final docs to:
|
|
71
|
+
- `README.md` — project overview and quick start
|
|
72
|
+
- `docs/API.md` — complete API reference
|
|
73
|
+
- `docs/USER_GUIDE.md` — detailed usage guide
|
|
74
|
+
|
|
75
|
+
## Output
|
|
76
|
+
|
|
77
|
+
Updated documentation files with:
|
|
78
|
+
- Accurate function signatures
|
|
79
|
+
- Working code examples
|
|
80
|
+
- Clear explanations of behavior
|
|
49
81
|
|
|
50
82
|
Report: files written/updated, public APIs documented, any gaps found.
|
package/src/rules/README.md
CHANGED
|
@@ -2,22 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
Coding standards for projects using FlowDeck. These define conventions that FlowDeck agents follow automatically.
|
|
4
4
|
|
|
5
|
-
## How
|
|
5
|
+
## How It Works
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Rules are loaded **automatically** by the FlowDeck plugin. No manual configuration is needed — when FlowDeck is installed, all rule files in this directory are injected into OpenCode's `instructions` at startup.
|
|
8
|
+
|
|
9
|
+
## Selective Rules (Optional)
|
|
10
|
+
|
|
11
|
+
If you want to override the default set and load only specific rules, add them to `opencode.json` under `instructions`:
|
|
8
12
|
|
|
9
13
|
```json
|
|
10
14
|
{
|
|
11
15
|
"instructions": [
|
|
12
|
-
".flowdeck/rules/common/coding-style.md",
|
|
13
|
-
".flowdeck/rules/
|
|
14
|
-
".flowdeck/rules/typescript/patterns.md"
|
|
16
|
+
"node_modules/@dv.nghiem/flowdeck/src/rules/common/coding-style.md",
|
|
17
|
+
"node_modules/@dv.nghiem/flowdeck/src/rules/typescript/patterns.md"
|
|
15
18
|
]
|
|
16
19
|
}
|
|
17
20
|
```
|
|
18
21
|
|
|
19
|
-
Agents will read these files and follow the conventions defined in them.
|
|
20
|
-
|
|
21
22
|
## Available Rules
|
|
22
23
|
|
|
23
24
|
### Common Rules (language-agnostic)
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-harness-construction
|
|
3
|
+
description: Build autonomous agent pipelines — construct agent loops, wire multi-agent orchestration, implement self-healing retry logic, and measure agent effectiveness
|
|
4
|
+
origin: FlowDeck
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Agent Harness Construction Skill
|
|
8
|
+
|
|
9
|
+
Constructs autonomous agent pipelines that can plan, execute, self-correct, and measure their own effectiveness.
|
|
10
|
+
|
|
11
|
+
## When to Activate
|
|
12
|
+
|
|
13
|
+
Activate when:
|
|
14
|
+
- Building multi-agent orchestration systems
|
|
15
|
+
- Implementing autonomous loops (self-correcting agents)
|
|
16
|
+
- Designing agent retry and self-healing policies
|
|
17
|
+
- Wiring agent-to-agent communication
|
|
18
|
+
- Measuring and optimizing agent effectiveness
|
|
19
|
+
|
|
20
|
+
## Agent Loop Architecture
|
|
21
|
+
|
|
22
|
+
### Core Loop Pattern
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
┌─────────────────────────────────────────────┐
|
|
26
|
+
│ 1. OBSERVE → Gather context state │
|
|
27
|
+
│ 2. THINK → Plan next action │
|
|
28
|
+
│ 3. ACT → Execute tool call │
|
|
29
|
+
│ 4. EVALUATE → Check result quality │
|
|
30
|
+
│ 5. ADAPT → Retry or proceed │
|
|
31
|
+
└─────────────────────────────────────────────┘
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
interface AgentLoop {
|
|
36
|
+
observe: () => Promise<Context>;
|
|
37
|
+
think: (ctx: Context) => Promise<Plan>;
|
|
38
|
+
act: (plan: Plan) => Promise<Result>;
|
|
39
|
+
evaluate: (result: Result) => Evaluation;
|
|
40
|
+
adapt: (evaluation: Evaluation) => 'continue' | 'retry' | 'complete';
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Self-Healing Retry Logic
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
async function withRetry<T>(
|
|
48
|
+
fn: () => Promise<T>,
|
|
49
|
+
options: {
|
|
50
|
+
maxAttempts?: number;
|
|
51
|
+
backoff?: 'linear' | 'exponential';
|
|
52
|
+
onRetry?: (attempt: number, error: Error) => void;
|
|
53
|
+
} = {}
|
|
54
|
+
): Promise<T> {
|
|
55
|
+
const { maxAttempts = 3, backoff = 'exponential', onRetry } = options;
|
|
56
|
+
|
|
57
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
58
|
+
try {
|
|
59
|
+
return await fn();
|
|
60
|
+
} catch (error) {
|
|
61
|
+
if (attempt === maxAttempts) throw error;
|
|
62
|
+
const delay = backoff === 'exponential'
|
|
63
|
+
? Math.pow(2, attempt - 1) * 1000
|
|
64
|
+
: attempt * 1000;
|
|
65
|
+
onRetry?.(attempt, error as Error);
|
|
66
|
+
await sleep(delay);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
throw new Error('unreachable');
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Multi-Agent Orchestration
|
|
74
|
+
|
|
75
|
+
### Supervisor Pattern
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
interface AgentMessage {
|
|
79
|
+
from: string;
|
|
80
|
+
to: string;
|
|
81
|
+
type: 'request' | 'response' | 'delegate' | 'result';
|
|
82
|
+
payload: unknown;
|
|
83
|
+
traceId: string;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
class SupervisorAgent {
|
|
87
|
+
private agents: Map<string, Agent>;
|
|
88
|
+
private messageQueue: AgentMessage[] = [];
|
|
89
|
+
|
|
90
|
+
async delegate(task: Task, targetAgent: string): Promise<Result> {
|
|
91
|
+
const message: AgentMessage = {
|
|
92
|
+
from: this.id,
|
|
93
|
+
to: targetAgent,
|
|
94
|
+
type: 'delegate',
|
|
95
|
+
payload: task,
|
|
96
|
+
traceId: generateTraceId(),
|
|
97
|
+
};
|
|
98
|
+
return this.sendAndWait(message);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async parallelDelegate(tasks: Task[], agents: string[]): Promise<Result[]> {
|
|
102
|
+
return Promise.all(
|
|
103
|
+
tasks.map((task, i) => this.delegate(task, agents[i % agents.length]))
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Council Pattern
|
|
110
|
+
|
|
111
|
+
Multiple agents deliberate and vote on a decision:
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
interface CouncilMember {
|
|
115
|
+
id: string;
|
|
116
|
+
specialty: 'security' | 'performance' | 'correctness';
|
|
117
|
+
vote: (proposal: Proposal) => Promise<Vote>;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
interface CouncilDecision {
|
|
121
|
+
votes: Vote[];
|
|
122
|
+
decision: 'approve' | 'reject' | 'revise';
|
|
123
|
+
consensus: number; // 0-1
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function councilDeliberate(
|
|
127
|
+
proposal: Proposal,
|
|
128
|
+
members: CouncilMember[]
|
|
129
|
+
): Promise<CouncilDecision> {
|
|
130
|
+
const votes = await Promise.all(members.map(m => m.vote(proposal)));
|
|
131
|
+
const approvals = votes.filter(v => v.approve).length;
|
|
132
|
+
const consensus = approvals / votes.length;
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
votes,
|
|
136
|
+
decision: consensus >= 0.7 ? 'approve' : consensus >= 0.4 ? 'revise' : 'reject',
|
|
137
|
+
consensus,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Agent Effectiveness Measurement
|
|
143
|
+
|
|
144
|
+
### Trace-Based Metrics
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
interface AgentTrace {
|
|
148
|
+
traceId: string;
|
|
149
|
+
agentId: string;
|
|
150
|
+
spans: {
|
|
151
|
+
name: string;
|
|
152
|
+
startTime: number;
|
|
153
|
+
endTime: number;
|
|
154
|
+
success: boolean;
|
|
155
|
+
tokensUsed?: number;
|
|
156
|
+
error?: string;
|
|
157
|
+
}[];
|
|
158
|
+
outcome: 'success' | 'failure' | 'timeout';
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Track effectiveness
|
|
162
|
+
function measureAgentEffectiveness(traces: AgentTrace[]): AgentMetrics {
|
|
163
|
+
return {
|
|
164
|
+
successRate: traces.filter(t => t.outcome === 'success').length / traces.length,
|
|
165
|
+
avgDuration: traces.reduce((sum, t) => {
|
|
166
|
+
const duration = t.spans[t.spans.length - 1].endTime - t.spans[0].startTime;
|
|
167
|
+
return sum + duration;
|
|
168
|
+
}, 0) / traces.length,
|
|
169
|
+
avgTokensPerTask: traces.reduce((sum, t) =>
|
|
170
|
+
sum + (t.spans.reduce((s, span) => s + (span.tokensUsed ?? 0), 0) / t.spans.length), 0
|
|
171
|
+
) / traces.length,
|
|
172
|
+
retryRate: traces.filter(t => t.spans.some(s => s.name === 'retry')).length / traces.length,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Error Classification
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
type ErrorCategory =
|
|
181
|
+
| 'transient' // Network blip, timeout — retry eligible
|
|
182
|
+
| 'recoverable' // Missing context, bad input — can fix with adaptation
|
|
183
|
+
| 'fatal'; // Auth failure, permission — cannot proceed
|
|
184
|
+
|
|
185
|
+
function classifyError(error: Error): ErrorCategory {
|
|
186
|
+
if (error.message.includes('timeout') || error.message.includes('ECONNREFUSED')) {
|
|
187
|
+
return 'transient';
|
|
188
|
+
}
|
|
189
|
+
if (error.message.includes('invalid input') || error.message.includes('missing context')) {
|
|
190
|
+
return 'recoverable';
|
|
191
|
+
}
|
|
192
|
+
return 'fatal';
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Self-Healing Policies
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
interface HealingPolicy {
|
|
200
|
+
trigger: (error: Error) => boolean;
|
|
201
|
+
action: (context: AgentContext) => Promise<Action>;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const healingPolicies: HealingPolicy[] = [
|
|
205
|
+
{
|
|
206
|
+
trigger: (e) => e.message.includes('rate limit'),
|
|
207
|
+
action: async (ctx) => {
|
|
208
|
+
ctx.throttleDelay = Math.min(ctx.throttleDelay * 2, 60000);
|
|
209
|
+
return { type: 'backoff', delay: ctx.throttleDelay };
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
trigger: (e) => e.message.includes('context too long'),
|
|
214
|
+
action: async (ctx) => {
|
|
215
|
+
ctx.summarizeOlderHistory();
|
|
216
|
+
return { type: 'compact' };
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
];
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Related Skills
|
|
223
|
+
|
|
224
|
+
- [self-healing-policies](self-healing-policies) — Define recovery policies
|
|
225
|
+
- [agent-introspection-debugging](agent-introspection-debugging) — Debug agent issues
|
|
226
|
+
- [eval-harness](eval-harness) — Evaluate agent performance
|
|
227
|
+
- [continuous-agent-loop](continuous-agent-loop) — Maintain persistent agent sessions
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# backend-patterns
|
|
2
|
+
|
|
3
|
+
## When to Activate
|
|
4
|
+
When implementing backend services, APIs, or server-side logic. Use when designing service layers, data access patterns, or middleware.
|
|
5
|
+
|
|
6
|
+
## Steps
|
|
7
|
+
1. **Identify the service layer** - Determine if you need a service layer to orchestrate business logic
|
|
8
|
+
2. **Apply Repository Pattern** - Encapsulate data access behind repository interfaces for testability
|
|
9
|
+
3. **Use Dependency Injection** - Pass dependencies explicitly rather than creating them inside classes
|
|
10
|
+
4. **Implement error handling** - Add comprehensive error handling with appropriate HTTP status codes
|
|
11
|
+
5. **Add middleware/logging** - Log requests, responses, and errors consistently
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// Service Layer with Repository Pattern
|
|
17
|
+
interface UserRepository {
|
|
18
|
+
findById(id: string): Promise<User | null>;
|
|
19
|
+
findAll(filter?: UserFilter): Promise<User[]>;
|
|
20
|
+
create(attributes: CreateUserDTO): Promise<User>;
|
|
21
|
+
update(id: string, attributes: UpdateUserDTO): Promise<User>;
|
|
22
|
+
delete(id: string): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class UserService {
|
|
26
|
+
constructor(private readonly userRepository: UserRepository) {}
|
|
27
|
+
|
|
28
|
+
async getUser(id: string): Promise<User> {
|
|
29
|
+
const user = await this.userRepository.findById(id);
|
|
30
|
+
if (!user) {
|
|
31
|
+
throw new NotFoundError(`User with id ${id} not found`);
|
|
32
|
+
}
|
|
33
|
+
return user;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async createUser(dto: CreateUserDTO): Promise<User> {
|
|
37
|
+
const existing = await this.userRepository.findByEmail(dto.email);
|
|
38
|
+
if (existing) {
|
|
39
|
+
throw new ConflictError('User with this email already exists');
|
|
40
|
+
}
|
|
41
|
+
return this.userRepository.create(dto);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Dependency Injection Container
|
|
46
|
+
const container = new Container();
|
|
47
|
+
container.register('userRepository', () => new PostgresUserRepository());
|
|
48
|
+
container.register('userService', () => new UserService(container.resolve('userRepository')));
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
// Error Handling with Custom Exceptions
|
|
53
|
+
class AppError extends Error {
|
|
54
|
+
constructor(
|
|
55
|
+
message: string,
|
|
56
|
+
public readonly code: string,
|
|
57
|
+
public readonly statusCode: number = 500
|
|
58
|
+
) {
|
|
59
|
+
super(message);
|
|
60
|
+
this.name = 'AppError';
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
class NotFoundError extends AppError {
|
|
65
|
+
constructor(message: string) {
|
|
66
|
+
super(message, 'NOT_FOUND', 404);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
class ValidationError extends AppError {
|
|
71
|
+
constructor(
|
|
72
|
+
message: string,
|
|
73
|
+
public readonly details?: Record<string, string[]>
|
|
74
|
+
) {
|
|
75
|
+
super(message, 'VALIDATION_ERROR', 422);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Global Error Handler Middleware
|
|
80
|
+
function errorHandler(err: Error, req: Request, res: Response, next: NextFunction) {
|
|
81
|
+
if (err instanceof AppError) {
|
|
82
|
+
return res.status(err.statusCode).json({
|
|
83
|
+
error: {
|
|
84
|
+
code: err.code,
|
|
85
|
+
message: err.message,
|
|
86
|
+
details: err instanceof ValidationError ? err.details : undefined,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
console.error('Unhandled error:', err);
|
|
91
|
+
return res.status(500).json({
|
|
92
|
+
error: {
|
|
93
|
+
code: 'INTERNAL_ERROR',
|
|
94
|
+
message: 'An unexpected error occurred',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Related Skills
|
|
101
|
+
- api-design
|
|
102
|
+
- postgres-patterns
|
|
103
|
+
- python-patterns
|
|
104
|
+
- layered-architecture
|
|
105
|
+
- ddd-architecture
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# clean-architecture
|
|
2
|
+
|
|
3
|
+
## When to Activate
|
|
4
|
+
When designing or implementing a new feature or service that needs clear separation of concerns, testability, and independence from frameworks, databases, or UI libraries.
|
|
5
|
+
|
|
6
|
+
## Steps
|
|
7
|
+
1. **Identify the core business logic** - Determine the essential domain rules that would exist even if the application had no UI, database, or external services.
|
|
8
|
+
2. **Define the boundary** - Draw a clear boundary between the inner circles (entities, use cases) and outer circles (interfaces, infrastructure).
|
|
9
|
+
3. **Place dependencies pointing inward** - Dependencies should always point toward the center. The inner circle knows nothing about the outer circle.
|
|
10
|
+
4. **Define ports (interfaces)** - Create interfaces in the domain layer that define how the outside world can interact with it.
|
|
11
|
+
5. **Implement adapters** - Create concrete implementations (adapters) for databases, web frameworks, external APIs, etc. in the outer layers.
|
|
12
|
+
6. **Wire everything via dependency injection** - Use a composition root or DI container to assemble the application.
|
|
13
|
+
|
|
14
|
+
## Examples
|
|
15
|
+
```typescript
|
|
16
|
+
// Domain Layer - Enterprise Business Rules (innermost circle)
|
|
17
|
+
class Order {
|
|
18
|
+
constructor(
|
|
19
|
+
private readonly id: string,
|
|
20
|
+
private readonly items: OrderItem[],
|
|
21
|
+
private readonly status: OrderStatus
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
get total(): number {
|
|
25
|
+
return this.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
canBeFulfilled(): boolean {
|
|
29
|
+
return this.status === 'pending' && this.items.length > 0
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Application Layer - Application Business Rules
|
|
34
|
+
interface OrderRepository {
|
|
35
|
+
findById(id: string): Promise<Order | null>
|
|
36
|
+
save(order: Order): Promise<void>
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface NotificationService {
|
|
40
|
+
sendOrderConfirmation(order: Order): Promise<void>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
class PlaceOrderUseCase {
|
|
44
|
+
constructor(
|
|
45
|
+
private readonly orderRepo: OrderRepository,
|
|
46
|
+
private readonly notifier: NotificationService
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
async execute(orderData: OrderData): Promise<Order> {
|
|
50
|
+
const order = new Order(orderData.id, orderData.items, 'pending')
|
|
51
|
+
|
|
52
|
+
if (!order.canBeFulfilled()) {
|
|
53
|
+
throw new InvalidOrderError('Order cannot be fulfilled')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await this.orderRepo.save(order)
|
|
57
|
+
await this.notifier.sendOrderConfirmation(order)
|
|
58
|
+
|
|
59
|
+
return order
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Infrastructure Layer - Interface Adapters (outermost circle)
|
|
64
|
+
class PostgresOrderRepository implements OrderRepository {
|
|
65
|
+
async findById(id: string): Promise<Order | null> {
|
|
66
|
+
// Database implementation
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async save(order: Order): Promise<void> {
|
|
70
|
+
// Database implementation
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
class EmailNotificationService implements NotificationService {
|
|
75
|
+
async sendOrderConfirmation(order: Order): Promise<void> {
|
|
76
|
+
// Email implementation
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Related Skills
|
|
82
|
+
- layered-architecture
|
|
83
|
+
- hexagonal-architecture
|
|
84
|
+
- ddd-architecture
|
|
85
|
+
- backend-patterns
|