@plaited/development-skills 0.3.5
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/.claude/commands/lsp-analyze.md +66 -0
- package/.claude/commands/lsp-find.md +51 -0
- package/.claude/commands/lsp-hover.md +48 -0
- package/.claude/commands/lsp-refs.md +55 -0
- package/.claude/commands/scaffold-rules.md +221 -0
- package/.claude/commands/validate-skill.md +29 -0
- package/.claude/rules/accuracy.md +64 -0
- package/.claude/rules/bun-apis.md +80 -0
- package/.claude/rules/code-review.md +276 -0
- package/.claude/rules/git-workflow.md +66 -0
- package/.claude/rules/github.md +154 -0
- package/.claude/rules/testing.md +125 -0
- package/.claude/settings.local.json +47 -0
- package/.claude/skills/code-documentation/SKILL.md +47 -0
- package/.claude/skills/code-documentation/references/internal-templates.md +113 -0
- package/.claude/skills/code-documentation/references/maintenance.md +164 -0
- package/.claude/skills/code-documentation/references/public-api-templates.md +100 -0
- package/.claude/skills/code-documentation/references/type-documentation.md +116 -0
- package/.claude/skills/code-documentation/references/workflow.md +60 -0
- package/.claude/skills/scaffold-rules/SKILL.md +97 -0
- package/.claude/skills/typescript-lsp/SKILL.md +239 -0
- package/.claude/skills/validate-skill/SKILL.md +105 -0
- package/LICENSE +15 -0
- package/README.md +149 -0
- package/bin/cli.ts +109 -0
- package/package.json +57 -0
- package/src/lsp-analyze.ts +223 -0
- package/src/lsp-client.ts +400 -0
- package/src/lsp-find.ts +100 -0
- package/src/lsp-hover.ts +87 -0
- package/src/lsp-references.ts +83 -0
- package/src/lsp-symbols.ts +73 -0
- package/src/resolve-file-path.ts +28 -0
- package/src/scaffold-rules.ts +435 -0
- package/src/tests/fixtures/sample.ts +27 -0
- package/src/tests/lsp-client.spec.ts +180 -0
- package/src/tests/resolve-file-path.spec.ts +33 -0
- package/src/tests/scaffold-rules.spec.ts +286 -0
- package/src/tests/validate-skill.spec.ts +231 -0
- package/src/validate-skill.ts +492 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
RULE TEMPLATE - Distributed via /scaffold-rules
|
|
3
|
+
Variables: {{#if development-skills}}, {{#if supports-slash-commands}}
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Code Review Standards
|
|
7
|
+
|
|
8
|
+
The following standards are not automatically enforced by Biome but should be checked during code review.
|
|
9
|
+
|
|
10
|
+
## Automated Validation
|
|
11
|
+
|
|
12
|
+
Before completing a code review, run these validation scripts:
|
|
13
|
+
|
|
14
|
+
### AgentSkills Validation
|
|
15
|
+
|
|
16
|
+
When working with AgentSkills directories (`.claude/skills/`, `.cursor/skills/`, `.factory/skills/`, etc.):
|
|
17
|
+
|
|
18
|
+
{{#if development-skills}}
|
|
19
|
+
**Validate structure:**
|
|
20
|
+
{{#if supports-slash-commands}}
|
|
21
|
+
```
|
|
22
|
+
/validate-skill <path>
|
|
23
|
+
```
|
|
24
|
+
{{/if}}
|
|
25
|
+
{{^if supports-slash-commands}}
|
|
26
|
+
```bash
|
|
27
|
+
bunx @plaited/development-skills validate-skill <path>
|
|
28
|
+
```
|
|
29
|
+
{{/if}}
|
|
30
|
+
|
|
31
|
+
This checks:
|
|
32
|
+
- SKILL.md exists with required frontmatter (name, description)
|
|
33
|
+
- Proper naming conventions
|
|
34
|
+
- Valid markdown references
|
|
35
|
+
{{/if}}
|
|
36
|
+
|
|
37
|
+
{{^if development-skills}}
|
|
38
|
+
Manually verify:
|
|
39
|
+
- SKILL.md exists with required frontmatter (name, description)
|
|
40
|
+
- Directory name matches skill name
|
|
41
|
+
- All referenced files exist
|
|
42
|
+
{{/if}}
|
|
43
|
+
|
|
44
|
+
## TypeScript Style Conventions
|
|
45
|
+
|
|
46
|
+
### Prefer `type` Over `interface`
|
|
47
|
+
|
|
48
|
+
Use type aliases instead of interfaces for better consistency and flexibility:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// ✅ Good
|
|
52
|
+
type User = {
|
|
53
|
+
name: string
|
|
54
|
+
email: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ❌ Avoid
|
|
58
|
+
interface User {
|
|
59
|
+
name: string
|
|
60
|
+
email: string
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Rationale:** Type aliases are more flexible (unions, intersections, mapped types) and provide consistent syntax across the codebase.
|
|
65
|
+
|
|
66
|
+
### No `any` Types
|
|
67
|
+
|
|
68
|
+
Always use proper types; use `unknown` if type is truly unknown and add type guards:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// ✅ Good
|
|
72
|
+
const process = (data: unknown) => {
|
|
73
|
+
if (typeof data === 'string') {
|
|
74
|
+
return data.toUpperCase()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ❌ Avoid
|
|
79
|
+
const process = (data: any) => {
|
|
80
|
+
return data.toUpperCase()
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### PascalCase for Types and Schemas
|
|
85
|
+
|
|
86
|
+
All type names use PascalCase. Zod schema names use `PascalCaseSchema` suffix:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// ✅ Good
|
|
90
|
+
type UserConfig = { /* ... */ }
|
|
91
|
+
const UserConfigSchema = z.object({ /* ... */ })
|
|
92
|
+
|
|
93
|
+
// ❌ Avoid
|
|
94
|
+
type userConfig = { /* ... */ }
|
|
95
|
+
const zUserConfig = z.object({ /* ... */ }) // Don't use z-prefix
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Arrow Functions Preferred
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// ✅ Good
|
|
102
|
+
const greet = (name: string) => `Hello, ${name}!`
|
|
103
|
+
|
|
104
|
+
// ❌ Avoid
|
|
105
|
+
function greet(name: string) {
|
|
106
|
+
return `Hello, ${name}!`
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Object Parameter Pattern
|
|
111
|
+
|
|
112
|
+
For functions with more than two parameters, use a single object parameter:
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// ✅ Good: Object parameter pattern
|
|
116
|
+
const createClient = ({
|
|
117
|
+
command,
|
|
118
|
+
timeout,
|
|
119
|
+
cwd,
|
|
120
|
+
}: {
|
|
121
|
+
command: string[]
|
|
122
|
+
timeout: number
|
|
123
|
+
cwd?: string
|
|
124
|
+
}): ACPClient => { /* ... */ }
|
|
125
|
+
|
|
126
|
+
// ❌ Avoid: Multiple positional parameters
|
|
127
|
+
const createClient = (
|
|
128
|
+
command: string[],
|
|
129
|
+
timeout: number,
|
|
130
|
+
cwd?: string
|
|
131
|
+
): ACPClient => { /* ... */ }
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## TypeScript Comment Directives
|
|
135
|
+
|
|
136
|
+
### `@ts-ignore` Requires Description
|
|
137
|
+
|
|
138
|
+
- When using `@ts-ignore`, always include a description explaining why the type error is being suppressed
|
|
139
|
+
- This helps future maintainers understand the reasoning
|
|
140
|
+
- Example:
|
|
141
|
+
```typescript
|
|
142
|
+
// @ts-ignore - TypeScript incorrectly infers this as string when it's actually a number from the API
|
|
143
|
+
const value = response.data
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Rationale:** Lost TypeScript-ESLint rule `ban-ts-comment` with `allow-with-description` option during Biome migration
|
|
147
|
+
|
|
148
|
+
## Expression Statements
|
|
149
|
+
|
|
150
|
+
### Allow Short-Circuit and Ternary Expressions
|
|
151
|
+
|
|
152
|
+
- Short-circuit evaluation is acceptable: `condition && doSomething()`
|
|
153
|
+
- Ternary expressions are acceptable: `condition ? doThis() : doThat()`
|
|
154
|
+
- These patterns are idiomatic and improve code readability
|
|
155
|
+
|
|
156
|
+
**Rationale:** Lost TypeScript-ESLint rule `no-unused-expressions` with `allowShortCircuit` and `allowTernary` options during Biome migration
|
|
157
|
+
|
|
158
|
+
## Empty Object Types
|
|
159
|
+
|
|
160
|
+
### Allow Empty Object Types When Extending a Single Interface
|
|
161
|
+
|
|
162
|
+
- Empty object types are acceptable when they extend exactly one other interface
|
|
163
|
+
- This pattern is useful for creating branded types or extending third-party interfaces
|
|
164
|
+
- Example:
|
|
165
|
+
```typescript
|
|
166
|
+
// ✅ Acceptable: Extends single interface
|
|
167
|
+
interface CustomElement extends HTMLElement {}
|
|
168
|
+
|
|
169
|
+
// ❌ Avoid: Empty with no extends or multiple extends
|
|
170
|
+
interface Empty {}
|
|
171
|
+
interface Multi extends Foo, Bar {}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Rationale:** Lost TypeScript-ESLint rule `no-empty-object-type` with `allowInterfaces: 'with-single-extends'` option during Biome migration
|
|
175
|
+
|
|
176
|
+
## Modern JavaScript Standards
|
|
177
|
+
|
|
178
|
+
### Prefer Private Fields Over `private` Keyword
|
|
179
|
+
|
|
180
|
+
Use JavaScript private fields (`#field`) instead of TypeScript's `private` keyword:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
// ✅ Good: JavaScript private fields (ES2022+)
|
|
184
|
+
class EventBus {
|
|
185
|
+
#listeners = new Map<string, Set<Function>>()
|
|
186
|
+
#count = 0
|
|
187
|
+
|
|
188
|
+
#emit(event: string) {
|
|
189
|
+
this.#count++
|
|
190
|
+
this.#listeners.get(event)?.forEach(fn => fn())
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ❌ Avoid: TypeScript private keyword
|
|
195
|
+
class EventBus {
|
|
196
|
+
private listeners = new Map<string, Set<Function>>()
|
|
197
|
+
private count = 0
|
|
198
|
+
|
|
199
|
+
private emit(event: string) {
|
|
200
|
+
this.count++
|
|
201
|
+
this.listeners.get(event)?.forEach(fn => fn())
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
**Rationale:** JavaScript private fields are a runtime feature (ES2022) providing true encapsulation. TypeScript's `private` is erased at compile time and can be bypassed. Prefer platform standards over TypeScript-only features
|
|
207
|
+
|
|
208
|
+
### JSON Import Attributes
|
|
209
|
+
|
|
210
|
+
Use import attributes when importing JSON files. This is required because the tsconfig uses `verbatimModuleSyntax: true` without `resolveJsonModule`:
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// ✅ Good: Import attribute for JSON
|
|
214
|
+
import { version } from '../package.json' with { type: 'json' }
|
|
215
|
+
import config from './config.json' with { type: 'json' }
|
|
216
|
+
|
|
217
|
+
// ❌ Avoid: Missing import attribute
|
|
218
|
+
import { version } from '../package.json'
|
|
219
|
+
import config from './config.json'
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
**Rationale:** Import attributes (ES2025) explicitly declare module types to the runtime. The `with { type: 'json' }` syntax is the standard (replacing the deprecated `assert` keyword). This provides runtime enforcement—if the file isn't valid JSON, the import fails.
|
|
223
|
+
|
|
224
|
+
## Module Organization
|
|
225
|
+
|
|
226
|
+
Organize module exports into separate files by category:
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
module/
|
|
230
|
+
├── module.types.ts # Type definitions only
|
|
231
|
+
├── module.schemas.ts # Zod schemas and schema-inferred types
|
|
232
|
+
├── module.constants.ts # Constants and enum-like objects
|
|
233
|
+
├── module-client.ts # Implementation
|
|
234
|
+
└── index.ts # Public API exports (barrel file)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Key Principles
|
|
238
|
+
|
|
239
|
+
- **Types file**: Contains only type definitions, does NOT re-export from sibling files
|
|
240
|
+
- **Schemas file**: Contains Zod schemas and their inferred types, does NOT export constants
|
|
241
|
+
- **Constants file**: Contains all constant values (error codes, method names, defaults)
|
|
242
|
+
- **Barrel file**: Uses wildcard exports; non-public files are simply not included
|
|
243
|
+
|
|
244
|
+
```typescript
|
|
245
|
+
// ✅ Good: Direct imports from specific files
|
|
246
|
+
import type { Config } from './module.types.ts'
|
|
247
|
+
import { ConfigSchema } from './module.schemas.ts'
|
|
248
|
+
import { METHODS, ERROR_CODES } from './module.constants.ts'
|
|
249
|
+
|
|
250
|
+
// ❌ Avoid: Expecting types file to re-export everything
|
|
251
|
+
import { Config, ConfigSchema, METHODS } from './module.types.ts'
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Rationale:** Prevents circular dependencies, makes dependencies explicit, improves tree-shaking.
|
|
255
|
+
|
|
256
|
+
## Documentation Standards
|
|
257
|
+
|
|
258
|
+
### Mermaid Diagrams Only
|
|
259
|
+
|
|
260
|
+
Use [mermaid](https://mermaid.js.org/) syntax for all diagrams in markdown files:
|
|
261
|
+
|
|
262
|
+
```markdown
|
|
263
|
+
\```mermaid
|
|
264
|
+
flowchart TD
|
|
265
|
+
A[Start] --> B[Process]
|
|
266
|
+
B --> C[End]
|
|
267
|
+
\```
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
**Avoid**: ASCII box-drawing characters (`┌`, `│`, `└`, `─`, etc.)
|
|
271
|
+
|
|
272
|
+
**Rationale:** Token efficiency, clearer semantic meaning, easier maintenance.
|
|
273
|
+
|
|
274
|
+
### No `@example` Sections in TSDoc
|
|
275
|
+
|
|
276
|
+
Tests serve as living examples. Do not add `@example` sections to TSDoc comments.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
RULE TEMPLATE - Distributed via /scaffold-rules
|
|
3
|
+
Variables: {{#if has-sandbox}}, {{#if supports-slash-commands}}
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Git Workflow
|
|
7
|
+
|
|
8
|
+
## Commit Message Format
|
|
9
|
+
|
|
10
|
+
{{#if has-sandbox}}
|
|
11
|
+
When creating commits with multi-line messages, use single-quoted strings instead of heredocs. The sandbox environment restricts temp file creation needed for heredocs.
|
|
12
|
+
{{/if}}
|
|
13
|
+
{{^if has-sandbox}}
|
|
14
|
+
Use multi-line commit messages for detailed changes:
|
|
15
|
+
{{/if}}
|
|
16
|
+
|
|
17
|
+
{{#if has-sandbox}}
|
|
18
|
+
```bash
|
|
19
|
+
# ✅ CORRECT: Single-quoted multi-line string
|
|
20
|
+
git commit -m 'refactor: description here
|
|
21
|
+
|
|
22
|
+
Additional context on second line.
|
|
23
|
+
|
|
24
|
+
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
|
25
|
+
|
|
26
|
+
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>'
|
|
27
|
+
|
|
28
|
+
# ❌ WRONG: Heredoc syntax (fails in sandbox)
|
|
29
|
+
git commit -m "$(cat <<'EOF'
|
|
30
|
+
refactor: description here
|
|
31
|
+
EOF
|
|
32
|
+
)"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The heredoc approach fails with:
|
|
36
|
+
```
|
|
37
|
+
(eval):1: can't create temp file for here document: operation not permitted
|
|
38
|
+
```
|
|
39
|
+
{{/if}}
|
|
40
|
+
{{^if has-sandbox}}
|
|
41
|
+
```bash
|
|
42
|
+
git commit -m "refactor: description here
|
|
43
|
+
|
|
44
|
+
Additional context on second line."
|
|
45
|
+
```
|
|
46
|
+
{{/if}}
|
|
47
|
+
|
|
48
|
+
## Pre-commit Hooks
|
|
49
|
+
|
|
50
|
+
**Never use `--no-verify`** to bypass pre-commit hooks. If hooks fail, it indicates a real issue that must be fixed:
|
|
51
|
+
|
|
52
|
+
1. Investigate the error message
|
|
53
|
+
2. Fix the underlying issue (lint errors, format issues, test failures)
|
|
54
|
+
3. Re-run the commit
|
|
55
|
+
|
|
56
|
+
Using `--no-verify` masks problems and defeats the purpose of automated quality checks.
|
|
57
|
+
|
|
58
|
+
## Commit Conventions
|
|
59
|
+
|
|
60
|
+
Follow conventional commits format:
|
|
61
|
+
- `feat:` - New features
|
|
62
|
+
- `fix:` - Bug fixes
|
|
63
|
+
- `refactor:` - Code changes that neither fix bugs nor add features
|
|
64
|
+
- `docs:` - Documentation only changes
|
|
65
|
+
- `chore:` - Maintenance tasks
|
|
66
|
+
- `test:` - Adding or updating tests
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# GitHub Integration
|
|
2
|
+
|
|
3
|
+
## Prefer GitHub CLI Over Web Fetch
|
|
4
|
+
|
|
5
|
+
When given GitHub URLs (PRs, issues, repos), use the `gh` CLI instead of WebFetch for more reliable and complete data access.
|
|
6
|
+
|
|
7
|
+
### PR Information
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Get PR details with comments and reviews (comprehensive)
|
|
11
|
+
gh pr view <number> --repo <owner>/<repo> --json title,body,comments,reviews,reviewRequests,state,author,additions,deletions,changedFiles
|
|
12
|
+
|
|
13
|
+
# Get PR diff
|
|
14
|
+
gh pr diff <number> --repo <owner>/<repo>
|
|
15
|
+
|
|
16
|
+
# Get PR files changed
|
|
17
|
+
gh pr view <number> --repo <owner>/<repo> --json files
|
|
18
|
+
|
|
19
|
+
# Get PR checks status
|
|
20
|
+
gh pr checks <number> --repo <owner>/<repo>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Complete PR Evaluation Workflow
|
|
24
|
+
|
|
25
|
+
When asked to evaluate PR feedback, you MUST fetch **all** feedback sources. Do not just fetch comments/reviews - also check security alerts and inline code comments.
|
|
26
|
+
|
|
27
|
+
**Step 1: Fetch PR comments and reviews**
|
|
28
|
+
```bash
|
|
29
|
+
gh pr view <number> --repo <owner>/<repo> --json title,body,comments,reviews,state
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Step 2: Fetch code scanning alerts (security vulnerabilities)**
|
|
33
|
+
```bash
|
|
34
|
+
gh api repos/<owner>/<repo>/code-scanning/alerts --jq '
|
|
35
|
+
.[] | select(.state == "open") | {
|
|
36
|
+
number: .number,
|
|
37
|
+
rule: .rule.description,
|
|
38
|
+
severity: .rule.severity,
|
|
39
|
+
file: .most_recent_instance.location.path,
|
|
40
|
+
line: .most_recent_instance.location.start_line
|
|
41
|
+
}
|
|
42
|
+
'
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Step 3: Fetch inline review comments (code quality, suggestions)**
|
|
46
|
+
```bash
|
|
47
|
+
gh api repos/<owner>/<repo>/pulls/<number>/comments --jq '
|
|
48
|
+
.[] | {
|
|
49
|
+
id: .id,
|
|
50
|
+
user: .user.login,
|
|
51
|
+
file: .path,
|
|
52
|
+
line: .line,
|
|
53
|
+
body: .body
|
|
54
|
+
}
|
|
55
|
+
'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Step 4: Address ALL feedback**
|
|
59
|
+
Create a checklist and address each item:
|
|
60
|
+
- [ ] Human reviewer comments
|
|
61
|
+
- [ ] Claude Code review comments
|
|
62
|
+
- [ ] GitHub Advanced Security alerts (ReDoS, injection, etc.)
|
|
63
|
+
- [ ] GitHub Code Quality comments (dead code, useless assignments)
|
|
64
|
+
- [ ] Inline review suggestions
|
|
65
|
+
|
|
66
|
+
### Comment Sources
|
|
67
|
+
|
|
68
|
+
| Source | API/Location | Description |
|
|
69
|
+
|--------|--------------|-------------|
|
|
70
|
+
| Human reviewers | `gh pr view --json reviews` | Code owners, team members |
|
|
71
|
+
| Claude Code | `gh pr view --json comments` | AI-generated review (login: `claude`) |
|
|
72
|
+
| GitHub Advanced Security | `gh api .../code-scanning/alerts` | Security vulnerabilities (ReDoS, injection) |
|
|
73
|
+
| GitHub Code Quality | `gh api .../pulls/.../comments` | Code quality issues (login: `github-code-quality[bot]`) |
|
|
74
|
+
| Inline suggestions | `gh api .../pulls/.../comments` | Line-specific review comments |
|
|
75
|
+
|
|
76
|
+
### Filtering by Author
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Get all automated reviews from PR
|
|
80
|
+
gh pr view <number> --repo <owner>/<repo> --json reviews --jq '
|
|
81
|
+
.reviews[] | select(.author.login | test("github-|claude")) | {author: .author.login, state: .state}
|
|
82
|
+
'
|
|
83
|
+
|
|
84
|
+
# Get specific inline comment by ID
|
|
85
|
+
gh api repos/<owner>/<repo>/pulls/<number>/comments --jq '
|
|
86
|
+
.[] | select(.id == <comment_id>)
|
|
87
|
+
'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### URL Patterns for Specific Feedback
|
|
91
|
+
|
|
92
|
+
| URL Pattern | How to Fetch |
|
|
93
|
+
|-------------|--------------|
|
|
94
|
+
| `.../pull/<n>#issuecomment-<id>` | `gh pr view <n> --json comments` |
|
|
95
|
+
| `.../pull/<n>#discussion_r<id>` | `gh api repos/.../pulls/<n>/comments` |
|
|
96
|
+
| `.../security/code-scanning/<id>` | `gh api repos/.../code-scanning/alerts/<id>` |
|
|
97
|
+
|
|
98
|
+
### Review States
|
|
99
|
+
- `APPROVED` - Reviewer approved changes
|
|
100
|
+
- `CHANGES_REQUESTED` - Reviewer requested changes
|
|
101
|
+
- `COMMENTED` - Review with comments only
|
|
102
|
+
- `PENDING` - Review not yet submitted
|
|
103
|
+
|
|
104
|
+
### Issue Information
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Get issue details
|
|
108
|
+
gh issue view <number> --repo <owner>/<repo> --json title,body,comments,state,author
|
|
109
|
+
|
|
110
|
+
# List issues
|
|
111
|
+
gh issue list --repo <owner>/<repo> --json number,title,state
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Repository Information
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# Get repo info
|
|
118
|
+
gh repo view <owner>/<repo> --json name,description,url
|
|
119
|
+
|
|
120
|
+
# List workflows
|
|
121
|
+
gh workflow list --repo <owner>/<repo>
|
|
122
|
+
|
|
123
|
+
# View run logs
|
|
124
|
+
gh run view <run-id> --repo <owner>/<repo> --log
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### URL Parsing
|
|
128
|
+
|
|
129
|
+
When given a GitHub URL, extract the components:
|
|
130
|
+
|
|
131
|
+
| URL Pattern | Command |
|
|
132
|
+
|-------------|---------|
|
|
133
|
+
| `github.com/<owner>/<repo>/pull/<number>` | `gh pr view <number> --repo <owner>/<repo>` |
|
|
134
|
+
| `github.com/<owner>/<repo>/issues/<number>` | `gh issue view <number> --repo <owner>/<repo>` |
|
|
135
|
+
| `github.com/<owner>/<repo>` | `gh repo view <owner>/<repo>` |
|
|
136
|
+
| `github.com/<owner>/<repo>/actions/runs/<id>` | `gh run view <id> --repo <owner>/<repo>` |
|
|
137
|
+
|
|
138
|
+
### JSON Output Fields
|
|
139
|
+
|
|
140
|
+
Common useful JSON fields for PRs:
|
|
141
|
+
- `title`, `body`, `state`, `author`
|
|
142
|
+
- `comments` - PR comments
|
|
143
|
+
- `reviews` - Review comments and approvals
|
|
144
|
+
- `additions`, `deletions`, `changedFiles`
|
|
145
|
+
- `files` - List of changed files
|
|
146
|
+
- `commits` - Commit history
|
|
147
|
+
|
|
148
|
+
### Benefits Over WebFetch
|
|
149
|
+
|
|
150
|
+
1. **Complete data** - Access to all comments, reviews, and metadata
|
|
151
|
+
2. **Authentication** - Uses configured GitHub credentials
|
|
152
|
+
3. **Structured output** - JSON format for reliable parsing
|
|
153
|
+
4. **No rate limiting issues** - Authenticated requests have higher limits
|
|
154
|
+
5. **Access to private repos** - Works with repos you have access to
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
RULE TEMPLATE - Distributed via /scaffold-rules
|
|
3
|
+
Variables: {{#if agent:claude}}
|
|
4
|
+
-->
|
|
5
|
+
|
|
6
|
+
# Testing
|
|
7
|
+
|
|
8
|
+
Use Bun's built-in test runner for unit and integration tests.
|
|
9
|
+
|
|
10
|
+
## Test Types
|
|
11
|
+
|
|
12
|
+
### Unit/Integration Tests (`*.spec.ts`)
|
|
13
|
+
|
|
14
|
+
Standard Bun tests using `*.spec.ts` extension:
|
|
15
|
+
- Run with `bun test` command
|
|
16
|
+
- Used for testing business logic, utilities, and non-visual functionality
|
|
17
|
+
|
|
18
|
+
## Running Tests
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
# Run all unit tests
|
|
22
|
+
bun test
|
|
23
|
+
|
|
24
|
+
# Run a specific spec test file
|
|
25
|
+
bun test path/to/file.spec.ts
|
|
26
|
+
|
|
27
|
+
# Run tests matching a pattern
|
|
28
|
+
bun test pattern
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Test Style Conventions
|
|
32
|
+
|
|
33
|
+
### Use `test` Instead of `it`
|
|
34
|
+
|
|
35
|
+
Use `test` instead of `it` in test files for consistency:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// ✅ Good
|
|
39
|
+
test('should create ACP client correctly', () => {
|
|
40
|
+
// ...
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
// ❌ Avoid
|
|
44
|
+
it('should create ACP client correctly', () => {
|
|
45
|
+
// ...
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Anti-Patterns
|
|
50
|
+
|
|
51
|
+
### No Conditionals Around Assertions
|
|
52
|
+
|
|
53
|
+
Never wrap assertions in conditionals. Tests should fail explicitly, not silently skip assertions.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// ❌ WRONG: Conditional assertion
|
|
57
|
+
if (result) {
|
|
58
|
+
expect(result.value).toBe(expected)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ❌ WRONG: Optional chaining with assertion
|
|
62
|
+
result?.value && expect(result.value).toBe(expected)
|
|
63
|
+
|
|
64
|
+
// ✅ CORRECT: Assert the condition, then assert the value
|
|
65
|
+
expect(result).toBeDefined()
|
|
66
|
+
expect(result.value).toBe(expected)
|
|
67
|
+
|
|
68
|
+
// ✅ CORRECT: Use type narrowing assertion
|
|
69
|
+
expect(result).not.toBeNull()
|
|
70
|
+
expect(result!.value).toBe(expected)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If a value might not exist, the test should either:
|
|
74
|
+
1. Assert that it exists first, then check its value
|
|
75
|
+
2. Assert that it doesn't exist (if that's the expected behavior)
|
|
76
|
+
3. Restructure the test to ensure the value is always present
|
|
77
|
+
|
|
78
|
+
## Docker Integration Tests
|
|
79
|
+
|
|
80
|
+
Tests that require external services or API keys can run in Docker containers for consistent, isolated execution.
|
|
81
|
+
|
|
82
|
+
### File Naming
|
|
83
|
+
|
|
84
|
+
- **`*.docker.ts`**: Tests that run in Docker containers
|
|
85
|
+
- These are excluded from `bun test` and run separately via Docker Compose
|
|
86
|
+
|
|
87
|
+
### Running Docker Tests
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Run with Docker Compose (requires API key)
|
|
91
|
+
ANTHROPIC_API_KEY=sk-... docker compose -f docker-compose.test.yml run --rm test
|
|
92
|
+
|
|
93
|
+
# Or using an npm script if configured
|
|
94
|
+
ANTHROPIC_API_KEY=sk-... bun run test:docker
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### CI Workflow Pattern
|
|
98
|
+
|
|
99
|
+
Docker tests can use path filtering to reduce API costs:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
# .github/workflows/ci.yml
|
|
103
|
+
jobs:
|
|
104
|
+
changes:
|
|
105
|
+
# Detects which paths changed
|
|
106
|
+
steps:
|
|
107
|
+
- uses: dorny/paths-filter@v3
|
|
108
|
+
with:
|
|
109
|
+
filters: |
|
|
110
|
+
integration:
|
|
111
|
+
- 'src/**'
|
|
112
|
+
|
|
113
|
+
test-integration:
|
|
114
|
+
needs: changes
|
|
115
|
+
if: ${{ needs.changes.outputs.integration == 'true' }}
|
|
116
|
+
# Only runs when src/ files change
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### When to Use Docker Tests
|
|
120
|
+
|
|
121
|
+
Use Docker for tests that:
|
|
122
|
+
- Require external API calls (Anthropic, OpenAI, etc.)
|
|
123
|
+
- Need specific environment configurations
|
|
124
|
+
- Should be isolated from the local development environment
|
|
125
|
+
- Are expensive to run and should be gated in CI
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(bun test:*)",
|
|
5
|
+
"Bash(bun run check:*)",
|
|
6
|
+
"Bash(bun run check:write:*)",
|
|
7
|
+
"WebFetch(domain:raw.githubusercontent.com)",
|
|
8
|
+
"Bash(gh repo view:*)",
|
|
9
|
+
"Bash(gh api:*)",
|
|
10
|
+
"Bash(gh repo edit:*)",
|
|
11
|
+
"Bash(git commit:*)",
|
|
12
|
+
"Bash(git push:*)",
|
|
13
|
+
"Bash(gh pr create:*)",
|
|
14
|
+
"Bash(git add:*)",
|
|
15
|
+
"Bash(gh run view:*)",
|
|
16
|
+
"Bash(bunx biome check:*)",
|
|
17
|
+
"Bash(git checkout:*)",
|
|
18
|
+
"mcp__agent-skills-spec__SearchAgentSkills",
|
|
19
|
+
"Bash(bunx lint-staged:*)",
|
|
20
|
+
"Bash(git revert:*)",
|
|
21
|
+
"Bash(bun biome check:*)",
|
|
22
|
+
"Bash(bun scripts/fast-find.ts:*)",
|
|
23
|
+
"mcp__bun-docs__SearchBun",
|
|
24
|
+
"Bash(bun scripts/scan-imports.ts:*)",
|
|
25
|
+
"Bash(bun:*)",
|
|
26
|
+
"Bash(ls:*)",
|
|
27
|
+
"Bash(gh pr view:*)",
|
|
28
|
+
"Bash(gh pr diff:*)",
|
|
29
|
+
"Bash(grep:*)",
|
|
30
|
+
"Bash(echo:*)",
|
|
31
|
+
"WebSearch",
|
|
32
|
+
"Bash(gh pr comment:*)",
|
|
33
|
+
"WebFetch(domain:github.com)",
|
|
34
|
+
"WebFetch(domain:aiengineerguide.com)",
|
|
35
|
+
"Bash(DEBUG_SCAFFOLD=1 bun bin/cli.ts:*)",
|
|
36
|
+
"WebFetch(domain:cursor.com)",
|
|
37
|
+
"WebFetch(domain:docs.factory.ai)",
|
|
38
|
+
"WebFetch(domain:agents.md)",
|
|
39
|
+
"Bash(git cherry-pick:*)"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"enableAllProjectMcpServers": true,
|
|
43
|
+
"enabledMcpjsonServers": [
|
|
44
|
+
"agent-skills-spec"
|
|
45
|
+
],
|
|
46
|
+
"outputStyle": "Learning"
|
|
47
|
+
}
|