anvil-dev-framework 0.1.6
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 +719 -0
- package/VERSION +1 -0
- package/docs/ANVIL-REPO-IMPLEMENTATION-PLAN.md +441 -0
- package/docs/FIRST-SKILL-TUTORIAL.md +408 -0
- package/docs/INSTALLATION-RETRO-NOTES.md +458 -0
- package/docs/INSTALLATION.md +984 -0
- package/docs/anvil-hud.md +469 -0
- package/docs/anvil-init.md +255 -0
- package/docs/anvil-state.md +210 -0
- package/docs/boris-cherny-ralph-wiggum-insights.md +608 -0
- package/docs/command-reference.md +2022 -0
- package/docs/hooks-tts.md +368 -0
- package/docs/implementation-guide.md +810 -0
- package/docs/linear-github-integration.md +247 -0
- package/docs/local-issues.md +677 -0
- package/docs/patterns/README.md +419 -0
- package/docs/planning-responsibilities.md +139 -0
- package/docs/session-workflow.md +573 -0
- package/docs/simplification-plan-template.md +297 -0
- package/docs/simplification-principles.md +129 -0
- package/docs/specifications/CCS-RALPH-INTEGRATION-DESIGN.md +633 -0
- package/docs/specifications/CCS-RESEARCH-REPORT.md +169 -0
- package/docs/specifications/PLAN-ANV-verification-ralph-wiggum.md +403 -0
- package/docs/specifications/PLAN-parallel-tracks-anvil-memory-ccs.md +494 -0
- package/docs/specifications/SPEC-ANV-VRW/component-01-verify.md +208 -0
- package/docs/specifications/SPEC-ANV-VRW/component-02-stop-gate.md +226 -0
- package/docs/specifications/SPEC-ANV-VRW/component-03-posttooluse.md +209 -0
- package/docs/specifications/SPEC-ANV-VRW/component-04-ralph-wiggum.md +604 -0
- package/docs/specifications/SPEC-ANV-VRW/component-05-atomic-actions.md +311 -0
- package/docs/specifications/SPEC-ANV-VRW/component-06-verify-subagent.md +264 -0
- package/docs/specifications/SPEC-ANV-VRW/component-07-claude-md.md +363 -0
- package/docs/specifications/SPEC-ANV-VRW/index.md +182 -0
- package/docs/specifications/SPEC-ANV-anvil-memory.md +573 -0
- package/docs/specifications/SPEC-ANV-context-checkpoints.md +781 -0
- package/docs/specifications/SPEC-ANV-verification-ralph-wiggum.md +789 -0
- package/docs/sync.md +122 -0
- package/global/CLAUDE.md +140 -0
- package/global/agents/verify-app.md +164 -0
- package/global/commands/anvil-settings.md +527 -0
- package/global/commands/anvil-sync.md +121 -0
- package/global/commands/change.md +197 -0
- package/global/commands/clarify.md +252 -0
- package/global/commands/cleanup.md +292 -0
- package/global/commands/commit-push-pr.md +207 -0
- package/global/commands/decay-review.md +127 -0
- package/global/commands/discover.md +158 -0
- package/global/commands/doc-coverage.md +122 -0
- package/global/commands/evidence.md +307 -0
- package/global/commands/explore.md +121 -0
- package/global/commands/force-exit.md +135 -0
- package/global/commands/handoff.md +191 -0
- package/global/commands/healthcheck.md +302 -0
- package/global/commands/hud.md +84 -0
- package/global/commands/insights.md +319 -0
- package/global/commands/linear-setup.md +184 -0
- package/global/commands/lint-fix.md +198 -0
- package/global/commands/orient.md +510 -0
- package/global/commands/plan.md +228 -0
- package/global/commands/ralph.md +346 -0
- package/global/commands/ready.md +182 -0
- package/global/commands/release.md +305 -0
- package/global/commands/retro.md +96 -0
- package/global/commands/shard.md +166 -0
- package/global/commands/spec.md +227 -0
- package/global/commands/sprint.md +184 -0
- package/global/commands/tasks.md +228 -0
- package/global/commands/test-and-commit.md +151 -0
- package/global/commands/validate.md +132 -0
- package/global/commands/verify.md +251 -0
- package/global/commands/weekly-review.md +156 -0
- package/global/hooks/__pycache__/ralph_context_monitor.cpython-314.pyc +0 -0
- package/global/hooks/__pycache__/statusline_agent_sync.cpython-314.pyc +0 -0
- package/global/hooks/anvil_memory_observe.ts +322 -0
- package/global/hooks/anvil_memory_session.ts +166 -0
- package/global/hooks/anvil_memory_stop.ts +187 -0
- package/global/hooks/parse_transcript.py +116 -0
- package/global/hooks/post_merge_cleanup.sh +132 -0
- package/global/hooks/post_tool_format.sh +215 -0
- package/global/hooks/ralph_context_monitor.py +240 -0
- package/global/hooks/ralph_stop.sh +502 -0
- package/global/hooks/statusline.sh +1110 -0
- package/global/hooks/statusline_agent_sync.py +224 -0
- package/global/hooks/stop_gate.sh +250 -0
- package/global/lib/.claude/anvil-state.json +21 -0
- package/global/lib/__pycache__/agent_registry.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/claim_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coderabbit_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/config_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/coordination_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/doc_coverage_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/gate_logger.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/github_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/hygiene_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_models.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/issue_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_data_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/linear_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/local_provider.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/quality_service.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/ralph_state.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/state_manager.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/transcript_parser.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verification_runner.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_iteration.cpython-314.pyc +0 -0
- package/global/lib/__pycache__/verify_subagent.cpython-314.pyc +0 -0
- package/global/lib/agent_registry.py +995 -0
- package/global/lib/anvil-state.sh +435 -0
- package/global/lib/claim_service.py +515 -0
- package/global/lib/coderabbit_service.py +314 -0
- package/global/lib/config_service.py +423 -0
- package/global/lib/coordination_service.py +331 -0
- package/global/lib/doc_coverage_service.py +1305 -0
- package/global/lib/gate_logger.py +316 -0
- package/global/lib/github_service.py +310 -0
- package/global/lib/handoff_generator.py +775 -0
- package/global/lib/hygiene_service.py +712 -0
- package/global/lib/issue_models.py +257 -0
- package/global/lib/issue_provider.py +339 -0
- package/global/lib/linear_data_service.py +210 -0
- package/global/lib/linear_provider.py +987 -0
- package/global/lib/linear_provider.py.backup +671 -0
- package/global/lib/local_provider.py +486 -0
- package/global/lib/orient_fast.py +457 -0
- package/global/lib/quality_service.py +470 -0
- package/global/lib/ralph_prompt_generator.py +563 -0
- package/global/lib/ralph_state.py +1202 -0
- package/global/lib/state_manager.py +417 -0
- package/global/lib/transcript_parser.py +597 -0
- package/global/lib/verification_runner.py +557 -0
- package/global/lib/verify_iteration.py +490 -0
- package/global/lib/verify_subagent.py +250 -0
- package/global/skills/README.md +155 -0
- package/global/skills/quality-gates/SKILL.md +252 -0
- package/global/skills/skill-template/SKILL.md +109 -0
- package/global/skills/testing-strategies/SKILL.md +337 -0
- package/global/templates/CHANGE-template.md +105 -0
- package/global/templates/HANDOFF-template.md +63 -0
- package/global/templates/PLAN-template.md +111 -0
- package/global/templates/SPEC-template.md +93 -0
- package/global/templates/ralph/PROMPT.md.template +89 -0
- package/global/templates/ralph/fix_plan.md.template +31 -0
- package/global/templates/ralph/progress.txt.template +23 -0
- package/global/tests/__pycache__/test_doc_coverage.cpython-314.pyc +0 -0
- package/global/tests/test_doc_coverage.py +520 -0
- package/global/tests/test_issue_models.py +299 -0
- package/global/tests/test_local_provider.py +323 -0
- package/global/tools/README.md +178 -0
- package/global/tools/__pycache__/anvil-hud.cpython-314.pyc +0 -0
- package/global/tools/anvil-hud.py +3622 -0
- package/global/tools/anvil-hud.py.bak +3318 -0
- package/global/tools/anvil-issue.py +432 -0
- package/global/tools/anvil-memory/CLAUDE.md +49 -0
- package/global/tools/anvil-memory/README.md +42 -0
- package/global/tools/anvil-memory/bun.lock +25 -0
- package/global/tools/anvil-memory/bunfig.toml +9 -0
- package/global/tools/anvil-memory/package.json +23 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/context-monitor.test.ts +535 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/edge-cases.test.ts +645 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/fixtures.ts +363 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/index.ts +8 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/integration.test.ts +417 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/prompt-generator.test.ts +571 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/ralph-stop.test.ts +440 -0
- package/global/tools/anvil-memory/src/__tests__/ccs/test-utils.ts +252 -0
- package/global/tools/anvil-memory/src/__tests__/commands.test.ts +657 -0
- package/global/tools/anvil-memory/src/__tests__/db.test.ts +641 -0
- package/global/tools/anvil-memory/src/__tests__/hooks.test.ts +272 -0
- package/global/tools/anvil-memory/src/__tests__/performance.test.ts +427 -0
- package/global/tools/anvil-memory/src/__tests__/test-utils.ts +113 -0
- package/global/tools/anvil-memory/src/commands/checkpoint.ts +197 -0
- package/global/tools/anvil-memory/src/commands/get.ts +115 -0
- package/global/tools/anvil-memory/src/commands/init.ts +94 -0
- package/global/tools/anvil-memory/src/commands/observe.ts +163 -0
- package/global/tools/anvil-memory/src/commands/search.ts +112 -0
- package/global/tools/anvil-memory/src/db.ts +638 -0
- package/global/tools/anvil-memory/src/index.ts +205 -0
- package/global/tools/anvil-memory/src/types.ts +122 -0
- package/global/tools/anvil-memory/tsconfig.json +29 -0
- package/global/tools/ralph-loop.sh +359 -0
- package/package.json +45 -0
- package/scripts/anvil +822 -0
- package/scripts/extract_patterns.py +222 -0
- package/scripts/init-project.sh +541 -0
- package/scripts/install.sh +229 -0
- package/scripts/postinstall.js +41 -0
- package/scripts/rollback.sh +188 -0
- package/scripts/sync.sh +623 -0
- package/scripts/test-statusline.sh +248 -0
- package/scripts/update_claude_md.py +224 -0
- package/scripts/verify.sh +255 -0
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
# Creating Your First Skill
|
|
2
|
+
|
|
3
|
+
> A step-by-step guide to creating domain skills for Anvil.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When to Create a Skill vs Sub-Agent
|
|
8
|
+
|
|
9
|
+
Before creating anything, understand the distinction:
|
|
10
|
+
|
|
11
|
+
### Create a SKILL when:
|
|
12
|
+
- Domain knowledge needs to be referenced repeatedly
|
|
13
|
+
- Information is relatively static (conventions, patterns, references)
|
|
14
|
+
- Multiple contexts might need this knowledge
|
|
15
|
+
- You want on-demand loading (not always in context)
|
|
16
|
+
|
|
17
|
+
**Examples**: Testing patterns, API design conventions, security checklists, component standards
|
|
18
|
+
|
|
19
|
+
### Create a SUB-AGENT when:
|
|
20
|
+
- Task requires multi-step execution
|
|
21
|
+
- Work involves tool calls and decisions
|
|
22
|
+
- Task is self-contained with clear completion criteria
|
|
23
|
+
- You need focused, autonomous work
|
|
24
|
+
|
|
25
|
+
**Examples**: Code reviewer, PR description writer, test generator, documentation updater
|
|
26
|
+
|
|
27
|
+
### Decision Framework
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
Is it knowledge/reference material?
|
|
31
|
+
├── Yes → SKILL
|
|
32
|
+
└── No → Is it a multi-step workflow?
|
|
33
|
+
├── Yes → SUB-AGENT
|
|
34
|
+
└── No → Probably just inline instructions
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Skill Structure
|
|
40
|
+
|
|
41
|
+
Every skill follows this structure:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
.claude/skills/
|
|
45
|
+
└── [skill-name]/
|
|
46
|
+
├── SKILL.md # Required: Overview, triggers, when to use
|
|
47
|
+
├── conventions.md # Optional: Patterns and standards
|
|
48
|
+
├── references/ # Optional: Reference documentation
|
|
49
|
+
│ └── *.md
|
|
50
|
+
└── examples/ # Optional: Code examples
|
|
51
|
+
└── *.ts|*.tsx
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### SKILL.md Format
|
|
55
|
+
|
|
56
|
+
```markdown
|
|
57
|
+
---
|
|
58
|
+
name: [Human-readable name]
|
|
59
|
+
description: [One-line description]
|
|
60
|
+
triggers:
|
|
61
|
+
- [keyword1]
|
|
62
|
+
- [keyword2]
|
|
63
|
+
- [phrase that should load this skill]
|
|
64
|
+
version: 1.0.0
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
# [Skill Name]
|
|
68
|
+
|
|
69
|
+
## When to Use
|
|
70
|
+
[Clear criteria for when Claude should load this skill]
|
|
71
|
+
|
|
72
|
+
## Key Concepts
|
|
73
|
+
[Core domain knowledge]
|
|
74
|
+
|
|
75
|
+
## Patterns
|
|
76
|
+
[Specific patterns to follow]
|
|
77
|
+
|
|
78
|
+
## Anti-Patterns
|
|
79
|
+
[What to avoid]
|
|
80
|
+
|
|
81
|
+
## Checklist
|
|
82
|
+
[Verification steps]
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## Tutorial: Creating a "Testing Patterns" Skill
|
|
88
|
+
|
|
89
|
+
Let's create a real skill step-by-step.
|
|
90
|
+
|
|
91
|
+
### Step 1: Identify the Domain
|
|
92
|
+
|
|
93
|
+
Ask yourself:
|
|
94
|
+
- What knowledge do I repeatedly need to reference?
|
|
95
|
+
- What patterns do I want enforced consistently?
|
|
96
|
+
- What would a senior developer on this project know?
|
|
97
|
+
|
|
98
|
+
For this tutorial: **Testing patterns for a Next.js + Vitest + React Testing Library project.**
|
|
99
|
+
|
|
100
|
+
### Step 2: Create the Directory
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
mkdir -p .claude/skills/testing-patterns
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Step 3: Create SKILL.md
|
|
107
|
+
|
|
108
|
+
Create `.claude/skills/testing-patterns/SKILL.md`:
|
|
109
|
+
|
|
110
|
+
```markdown
|
|
111
|
+
---
|
|
112
|
+
name: Testing Patterns
|
|
113
|
+
description: Vitest + React Testing Library patterns for this project
|
|
114
|
+
triggers:
|
|
115
|
+
- test
|
|
116
|
+
- spec
|
|
117
|
+
- vitest
|
|
118
|
+
- testing library
|
|
119
|
+
- write tests
|
|
120
|
+
- unit test
|
|
121
|
+
- integration test
|
|
122
|
+
version: 1.0.0
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
# Testing Patterns
|
|
126
|
+
|
|
127
|
+
## When to Use
|
|
128
|
+
|
|
129
|
+
Load this skill when:
|
|
130
|
+
- Writing new tests
|
|
131
|
+
- Reviewing test code
|
|
132
|
+
- Debugging test failures
|
|
133
|
+
- Setting up test infrastructure
|
|
134
|
+
|
|
135
|
+
## Test File Organization
|
|
136
|
+
|
|
137
|
+
```
|
|
138
|
+
src/
|
|
139
|
+
├── components/
|
|
140
|
+
│ └── Button/
|
|
141
|
+
│ ├── Button.tsx
|
|
142
|
+
│ └── Button.test.tsx # Co-located
|
|
143
|
+
└── lib/
|
|
144
|
+
└── utils/
|
|
145
|
+
├── formatters.ts
|
|
146
|
+
└── formatters.test.ts # Co-located
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Test Structure
|
|
150
|
+
|
|
151
|
+
Use the Arrange-Act-Assert pattern:
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
describe('ComponentName', () => {
|
|
155
|
+
describe('when [condition]', () => {
|
|
156
|
+
it('should [expected behavior]', () => {
|
|
157
|
+
// Arrange
|
|
158
|
+
const props = { ... };
|
|
159
|
+
|
|
160
|
+
// Act
|
|
161
|
+
render(<Component {...props} />);
|
|
162
|
+
|
|
163
|
+
// Assert
|
|
164
|
+
expect(screen.getByRole('button')).toBeInTheDocument();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Query Priority
|
|
171
|
+
|
|
172
|
+
Follow Testing Library's query priority:
|
|
173
|
+
|
|
174
|
+
1. `getByRole` — Accessible queries (preferred)
|
|
175
|
+
2. `getByLabelText` — Form fields
|
|
176
|
+
3. `getByPlaceholderText` — When no label
|
|
177
|
+
4. `getByText` — Non-interactive elements
|
|
178
|
+
5. `getByTestId` — Last resort only
|
|
179
|
+
|
|
180
|
+
## Async Patterns
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// Waiting for elements
|
|
184
|
+
await waitFor(() => {
|
|
185
|
+
expect(screen.getByText('Loaded')).toBeInTheDocument();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Waiting for removal
|
|
189
|
+
await waitForElementToBeRemoved(() =>
|
|
190
|
+
screen.queryByText('Loading...')
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// User events (always async)
|
|
194
|
+
await user.click(button);
|
|
195
|
+
await user.type(input, 'text');
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Mocking Patterns
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// Mock modules
|
|
202
|
+
vi.mock('@/lib/api', () => ({
|
|
203
|
+
fetchUser: vi.fn(),
|
|
204
|
+
}));
|
|
205
|
+
|
|
206
|
+
// Mock implementations
|
|
207
|
+
const mockFetchUser = vi.mocked(fetchUser);
|
|
208
|
+
mockFetchUser.mockResolvedValue({ id: '1', name: 'Test' });
|
|
209
|
+
|
|
210
|
+
// Reset between tests
|
|
211
|
+
beforeEach(() => {
|
|
212
|
+
vi.clearAllMocks();
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Anti-Patterns
|
|
217
|
+
|
|
218
|
+
❌ **Don't test implementation details**
|
|
219
|
+
```typescript
|
|
220
|
+
// Bad: Testing internal state
|
|
221
|
+
expect(component.state.isOpen).toBe(true);
|
|
222
|
+
|
|
223
|
+
// Good: Testing user-visible behavior
|
|
224
|
+
expect(screen.getByRole('dialog')).toBeVisible();
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
❌ **Don't use arbitrary waits**
|
|
228
|
+
```typescript
|
|
229
|
+
// Bad
|
|
230
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
231
|
+
|
|
232
|
+
// Good
|
|
233
|
+
await waitFor(() => expect(...));
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
❌ **Don't rely on test order**
|
|
237
|
+
```typescript
|
|
238
|
+
// Bad: Shared mutable state between tests
|
|
239
|
+
let sharedData;
|
|
240
|
+
|
|
241
|
+
// Good: Fresh setup per test
|
|
242
|
+
beforeEach(() => {
|
|
243
|
+
sharedData = createTestData();
|
|
244
|
+
});
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
## Checklist
|
|
248
|
+
|
|
249
|
+
Before committing tests:
|
|
250
|
+
|
|
251
|
+
- [ ] Tests are co-located with source files
|
|
252
|
+
- [ ] Descriptive test names (reads like documentation)
|
|
253
|
+
- [ ] Using accessible queries (getByRole preferred)
|
|
254
|
+
- [ ] No arbitrary timeouts
|
|
255
|
+
- [ ] Mocks cleaned up in beforeEach/afterEach
|
|
256
|
+
- [ ] Edge cases covered (empty states, errors, loading)
|
|
257
|
+
- [ ] No console warnings in test output
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Step 4: Add Examples (Optional)
|
|
261
|
+
|
|
262
|
+
Create `.claude/skills/testing-patterns/examples/component.test.tsx`:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
/**
|
|
266
|
+
* Example: Complete component test
|
|
267
|
+
* Demonstrates patterns from SKILL.md
|
|
268
|
+
*/
|
|
269
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
270
|
+
import userEvent from '@testing-library/user-event';
|
|
271
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
272
|
+
|
|
273
|
+
import { UserProfile } from './UserProfile';
|
|
274
|
+
import { fetchUser } from '@/lib/api';
|
|
275
|
+
|
|
276
|
+
// Mock the API module
|
|
277
|
+
vi.mock('@/lib/api', () => ({
|
|
278
|
+
fetchUser: vi.fn(),
|
|
279
|
+
}));
|
|
280
|
+
|
|
281
|
+
describe('UserProfile', () => {
|
|
282
|
+
const user = userEvent.setup();
|
|
283
|
+
const mockFetchUser = vi.mocked(fetchUser);
|
|
284
|
+
|
|
285
|
+
beforeEach(() => {
|
|
286
|
+
vi.clearAllMocks();
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('when loading', () => {
|
|
290
|
+
it('should show loading spinner', () => {
|
|
291
|
+
mockFetchUser.mockReturnValue(new Promise(() => {})); // Never resolves
|
|
292
|
+
|
|
293
|
+
render(<UserProfile userId="1" />);
|
|
294
|
+
|
|
295
|
+
expect(screen.getByRole('status')).toHaveTextContent('Loading');
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
describe('when loaded successfully', () => {
|
|
300
|
+
it('should display user name', async () => {
|
|
301
|
+
mockFetchUser.mockResolvedValue({ id: '1', name: 'Jane Doe' });
|
|
302
|
+
|
|
303
|
+
render(<UserProfile userId="1" />);
|
|
304
|
+
|
|
305
|
+
await waitFor(() => {
|
|
306
|
+
expect(screen.getByRole('heading')).toHaveTextContent('Jane Doe');
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
describe('when user clicks edit', () => {
|
|
312
|
+
it('should open edit modal', async () => {
|
|
313
|
+
mockFetchUser.mockResolvedValue({ id: '1', name: 'Jane Doe' });
|
|
314
|
+
|
|
315
|
+
render(<UserProfile userId="1" />);
|
|
316
|
+
|
|
317
|
+
await waitFor(() => {
|
|
318
|
+
expect(screen.getByRole('heading')).toBeInTheDocument();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
await user.click(screen.getByRole('button', { name: /edit/i }));
|
|
322
|
+
|
|
323
|
+
expect(screen.getByRole('dialog')).toBeVisible();
|
|
324
|
+
});
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
describe('when API fails', () => {
|
|
328
|
+
it('should show error message', async () => {
|
|
329
|
+
mockFetchUser.mockRejectedValue(new Error('Network error'));
|
|
330
|
+
|
|
331
|
+
render(<UserProfile userId="1" />);
|
|
332
|
+
|
|
333
|
+
await waitFor(() => {
|
|
334
|
+
expect(screen.getByRole('alert')).toHaveTextContent('Failed to load');
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Step 5: Test the Skill
|
|
342
|
+
|
|
343
|
+
Start a Claude session and ask:
|
|
344
|
+
|
|
345
|
+
> "Help me write tests for the checkout flow"
|
|
346
|
+
|
|
347
|
+
Claude should:
|
|
348
|
+
1. Load the testing-patterns skill
|
|
349
|
+
2. Follow the patterns defined in SKILL.md
|
|
350
|
+
3. Use the query priority and async patterns
|
|
351
|
+
4. Avoid the anti-patterns
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## More Skill Ideas
|
|
356
|
+
|
|
357
|
+
| Skill | Triggers | Content |
|
|
358
|
+
|-------|----------|---------|
|
|
359
|
+
| `api-design` | api, endpoint, route, REST | API conventions, error handling, auth patterns |
|
|
360
|
+
| `component-patterns` | component, UI, React | Component structure, props, state management |
|
|
361
|
+
| `database-patterns` | database, query, Supabase, SQL | Query patterns, RLS, migrations |
|
|
362
|
+
| `security-patterns` | security, auth, validation | Auth flows, input validation, CSRF |
|
|
363
|
+
| `performance-patterns` | performance, optimize, slow | Caching, lazy loading, profiling |
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## Skill Triggers
|
|
368
|
+
|
|
369
|
+
Skills are loaded when Claude detects trigger keywords in the conversation.
|
|
370
|
+
|
|
371
|
+
### Good Triggers
|
|
372
|
+
- Specific: `vitest`, `supabase`, `shadcn`
|
|
373
|
+
- Action-oriented: `write tests`, `create component`
|
|
374
|
+
- Domain terms: `authentication`, `database query`
|
|
375
|
+
|
|
376
|
+
### Bad Triggers
|
|
377
|
+
- Too generic: `code`, `help`, `fix`
|
|
378
|
+
- Too rare: Jargon only you use
|
|
379
|
+
- Overlapping: Same triggers in multiple skills
|
|
380
|
+
|
|
381
|
+
### Updating Triggers
|
|
382
|
+
|
|
383
|
+
After using a skill, if you notice it should have loaded but didn't, add the missing trigger keyword to the SKILL.md frontmatter.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## Skill Maintenance
|
|
388
|
+
|
|
389
|
+
### When to Update
|
|
390
|
+
- New patterns emerge in your codebase
|
|
391
|
+
- Anti-patterns discovered
|
|
392
|
+
- Team conventions change
|
|
393
|
+
- New tools adopted
|
|
394
|
+
|
|
395
|
+
### Version Bumping
|
|
396
|
+
Increment the version in SKILL.md when making significant changes:
|
|
397
|
+
- Patch (1.0.1): Typo fixes, clarifications
|
|
398
|
+
- Minor (1.1.0): New patterns, examples
|
|
399
|
+
- Major (2.0.0): Breaking changes to conventions
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
## Next Steps
|
|
404
|
+
|
|
405
|
+
1. **Create one skill** for your most-referenced domain
|
|
406
|
+
2. **Use it for a week** — note what's missing
|
|
407
|
+
3. **Iterate** — add examples, refine patterns
|
|
408
|
+
4. **Create more** — as patterns emerge in your work
|