@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.
Files changed (40) hide show
  1. package/.claude/commands/lsp-analyze.md +66 -0
  2. package/.claude/commands/lsp-find.md +51 -0
  3. package/.claude/commands/lsp-hover.md +48 -0
  4. package/.claude/commands/lsp-refs.md +55 -0
  5. package/.claude/commands/scaffold-rules.md +221 -0
  6. package/.claude/commands/validate-skill.md +29 -0
  7. package/.claude/rules/accuracy.md +64 -0
  8. package/.claude/rules/bun-apis.md +80 -0
  9. package/.claude/rules/code-review.md +276 -0
  10. package/.claude/rules/git-workflow.md +66 -0
  11. package/.claude/rules/github.md +154 -0
  12. package/.claude/rules/testing.md +125 -0
  13. package/.claude/settings.local.json +47 -0
  14. package/.claude/skills/code-documentation/SKILL.md +47 -0
  15. package/.claude/skills/code-documentation/references/internal-templates.md +113 -0
  16. package/.claude/skills/code-documentation/references/maintenance.md +164 -0
  17. package/.claude/skills/code-documentation/references/public-api-templates.md +100 -0
  18. package/.claude/skills/code-documentation/references/type-documentation.md +116 -0
  19. package/.claude/skills/code-documentation/references/workflow.md +60 -0
  20. package/.claude/skills/scaffold-rules/SKILL.md +97 -0
  21. package/.claude/skills/typescript-lsp/SKILL.md +239 -0
  22. package/.claude/skills/validate-skill/SKILL.md +105 -0
  23. package/LICENSE +15 -0
  24. package/README.md +149 -0
  25. package/bin/cli.ts +109 -0
  26. package/package.json +57 -0
  27. package/src/lsp-analyze.ts +223 -0
  28. package/src/lsp-client.ts +400 -0
  29. package/src/lsp-find.ts +100 -0
  30. package/src/lsp-hover.ts +87 -0
  31. package/src/lsp-references.ts +83 -0
  32. package/src/lsp-symbols.ts +73 -0
  33. package/src/resolve-file-path.ts +28 -0
  34. package/src/scaffold-rules.ts +435 -0
  35. package/src/tests/fixtures/sample.ts +27 -0
  36. package/src/tests/lsp-client.spec.ts +180 -0
  37. package/src/tests/resolve-file-path.spec.ts +33 -0
  38. package/src/tests/scaffold-rules.spec.ts +286 -0
  39. package/src/tests/validate-skill.spec.ts +231 -0
  40. 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
+ }