devflow-kit 1.1.0 → 1.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/CHANGELOG.md +69 -1
- package/README.md +23 -6
- package/dist/cli.js +2 -0
- package/dist/commands/ambient.js +5 -4
- package/dist/commands/init.js +4 -2
- package/dist/commands/memory.js +4 -4
- package/dist/commands/skills.d.ts +11 -0
- package/dist/commands/skills.js +116 -0
- package/dist/commands/uninstall.js +11 -1
- package/dist/plugins.js +67 -3
- package/dist/utils/installer.js +20 -2
- package/package.json +4 -2
- package/plugins/devflow-accessibility/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-ambient/.claude-plugin/plugin.json +4 -2
- package/plugins/devflow-ambient/README.md +8 -8
- package/plugins/devflow-ambient/commands/ambient.md +14 -14
- package/plugins/devflow-ambient/skills/ambient-router/SKILL.md +16 -9
- package/plugins/devflow-ambient/skills/ambient-router/references/skill-catalog.md +6 -2
- package/plugins/devflow-audit-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/devflow-code-review/.claude-plugin/plugin.json +13 -6
- package/plugins/devflow-code-review/agents/reviewer.md +8 -0
- package/plugins/devflow-code-review/commands/code-review-teams.md +11 -1
- package/plugins/devflow-code-review/commands/code-review.md +12 -2
- package/plugins/devflow-code-review/skills/architecture-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/complexity-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/consistency-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/database-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/dependencies-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/documentation-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/performance-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/regression-patterns/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/review-methodology/SKILL.md +1 -1
- package/plugins/devflow-code-review/skills/security-patterns/SKILL.md +1 -1
- package/plugins/devflow-core-skills/.claude-plugin/plugin.json +10 -7
- package/plugins/devflow-core-skills/skills/test-driven-development/SKILL.md +5 -8
- package/plugins/devflow-debug/.claude-plugin/plugin.json +10 -3
- package/plugins/devflow-frontend-design/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-go/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-go/skills/go/SKILL.md +187 -0
- package/plugins/devflow-go/skills/go/references/concurrency.md +312 -0
- package/plugins/devflow-go/skills/go/references/detection.md +129 -0
- package/plugins/devflow-go/skills/go/references/patterns.md +232 -0
- package/plugins/devflow-go/skills/go/references/violations.md +205 -0
- package/plugins/devflow-implement/.claude-plugin/plugin.json +19 -5
- package/plugins/devflow-implement/agents/coder.md +11 -6
- package/plugins/devflow-implement/skills/self-review/SKILL.md +1 -1
- package/plugins/devflow-java/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-java/skills/java/SKILL.md +183 -0
- package/plugins/devflow-java/skills/java/references/detection.md +120 -0
- package/plugins/devflow-java/skills/java/references/modern-java.md +270 -0
- package/plugins/devflow-java/skills/java/references/patterns.md +235 -0
- package/plugins/devflow-java/skills/java/references/violations.md +213 -0
- package/plugins/devflow-python/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-python/skills/python/SKILL.md +188 -0
- package/plugins/devflow-python/skills/python/references/async.md +220 -0
- package/plugins/devflow-python/skills/python/references/detection.md +128 -0
- package/plugins/devflow-python/skills/python/references/patterns.md +226 -0
- package/plugins/devflow-python/skills/python/references/violations.md +204 -0
- package/plugins/devflow-react/.claude-plugin/plugin.json +22 -0
- package/plugins/{devflow-core-skills → devflow-react}/skills/react/SKILL.md +1 -1
- package/plugins/{devflow-core-skills → devflow-react}/skills/react/references/patterns.md +3 -3
- package/plugins/devflow-resolve/.claude-plugin/plugin.json +13 -3
- package/plugins/devflow-resolve/skills/security-patterns/SKILL.md +1 -1
- package/plugins/devflow-rust/.claude-plugin/plugin.json +22 -0
- package/plugins/devflow-rust/skills/rust/SKILL.md +193 -0
- package/plugins/devflow-rust/skills/rust/references/detection.md +131 -0
- package/plugins/devflow-rust/skills/rust/references/ownership.md +242 -0
- package/plugins/devflow-rust/skills/rust/references/patterns.md +210 -0
- package/plugins/devflow-rust/skills/rust/references/violations.md +191 -0
- package/plugins/devflow-self-review/.claude-plugin/plugin.json +10 -3
- package/plugins/devflow-self-review/skills/self-review/SKILL.md +1 -1
- package/plugins/devflow-specify/.claude-plugin/plugin.json +15 -4
- package/plugins/devflow-typescript/.claude-plugin/plugin.json +22 -0
- package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/patterns.md +3 -3
- package/scripts/hooks/{ambient-prompt.sh → ambient-prompt} +4 -4
- package/scripts/hooks/{background-memory-update.sh → background-memory-update} +3 -3
- package/scripts/hooks/{ensure-memory-gitignore.sh → ensure-memory-gitignore} +1 -1
- package/scripts/hooks/{pre-compact-memory.sh → pre-compact-memory} +2 -2
- package/scripts/hooks/run-hook +23 -0
- package/scripts/hooks/session-start-memory +151 -0
- package/scripts/hooks/{stop-update-memory.sh → stop-update-memory} +4 -4
- package/shared/agents/coder.md +11 -6
- package/shared/agents/reviewer.md +8 -0
- package/shared/skills/ambient-router/SKILL.md +16 -9
- package/shared/skills/ambient-router/references/skill-catalog.md +6 -2
- package/shared/skills/architecture-patterns/SKILL.md +1 -1
- package/shared/skills/complexity-patterns/SKILL.md +1 -1
- package/shared/skills/consistency-patterns/SKILL.md +1 -1
- package/shared/skills/database-patterns/SKILL.md +1 -1
- package/shared/skills/dependencies-patterns/SKILL.md +1 -1
- package/shared/skills/documentation-patterns/SKILL.md +1 -1
- package/shared/skills/go/SKILL.md +187 -0
- package/shared/skills/go/references/concurrency.md +312 -0
- package/shared/skills/go/references/detection.md +129 -0
- package/shared/skills/go/references/patterns.md +232 -0
- package/shared/skills/go/references/violations.md +205 -0
- package/shared/skills/java/SKILL.md +183 -0
- package/shared/skills/java/references/detection.md +120 -0
- package/shared/skills/java/references/modern-java.md +270 -0
- package/shared/skills/java/references/patterns.md +235 -0
- package/shared/skills/java/references/violations.md +213 -0
- package/shared/skills/performance-patterns/SKILL.md +1 -1
- package/shared/skills/python/SKILL.md +188 -0
- package/shared/skills/python/references/async.md +220 -0
- package/shared/skills/python/references/detection.md +128 -0
- package/shared/skills/python/references/patterns.md +226 -0
- package/shared/skills/python/references/violations.md +204 -0
- package/shared/skills/react/SKILL.md +1 -1
- package/shared/skills/react/references/patterns.md +3 -3
- package/shared/skills/regression-patterns/SKILL.md +1 -1
- package/shared/skills/review-methodology/SKILL.md +1 -1
- package/shared/skills/rust/SKILL.md +193 -0
- package/shared/skills/rust/references/detection.md +131 -0
- package/shared/skills/rust/references/ownership.md +242 -0
- package/shared/skills/rust/references/patterns.md +210 -0
- package/shared/skills/rust/references/violations.md +191 -0
- package/shared/skills/security-patterns/SKILL.md +1 -1
- package/shared/skills/self-review/SKILL.md +1 -1
- package/shared/skills/test-driven-development/SKILL.md +5 -8
- package/shared/skills/typescript/references/patterns.md +3 -3
- package/src/templates/settings.json +3 -3
- package/plugins/devflow-code-review/skills/react/SKILL.md +0 -276
- package/plugins/devflow-code-review/skills/react/references/patterns.md +0 -1331
- package/plugins/devflow-core-skills/skills/accessibility/SKILL.md +0 -229
- package/plugins/devflow-core-skills/skills/accessibility/references/detection.md +0 -171
- package/plugins/devflow-core-skills/skills/accessibility/references/patterns.md +0 -670
- package/plugins/devflow-core-skills/skills/accessibility/references/violations.md +0 -419
- package/plugins/devflow-core-skills/skills/frontend-design/SKILL.md +0 -254
- package/plugins/devflow-core-skills/skills/frontend-design/references/detection.md +0 -184
- package/plugins/devflow-core-skills/skills/frontend-design/references/patterns.md +0 -511
- package/plugins/devflow-core-skills/skills/frontend-design/references/violations.md +0 -453
- package/plugins/devflow-core-skills/skills/react/references/violations.md +0 -565
- package/plugins/devflow-implement/skills/accessibility/SKILL.md +0 -229
- package/plugins/devflow-implement/skills/accessibility/references/detection.md +0 -171
- package/plugins/devflow-implement/skills/accessibility/references/patterns.md +0 -670
- package/plugins/devflow-implement/skills/accessibility/references/violations.md +0 -419
- package/plugins/devflow-implement/skills/frontend-design/SKILL.md +0 -254
- package/plugins/devflow-implement/skills/frontend-design/references/detection.md +0 -184
- package/plugins/devflow-implement/skills/frontend-design/references/patterns.md +0 -511
- package/plugins/devflow-implement/skills/frontend-design/references/violations.md +0 -453
- package/scripts/hooks/session-start-memory.sh +0 -126
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/SKILL.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/detection.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/patterns.md +0 -0
- /package/plugins/{devflow-code-review → devflow-accessibility}/skills/accessibility/references/violations.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/SKILL.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/detection.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/patterns.md +0 -0
- /package/plugins/{devflow-code-review → devflow-frontend-design}/skills/frontend-design/references/violations.md +0 -0
- /package/plugins/{devflow-code-review → devflow-react}/skills/react/references/violations.md +0 -0
- /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/SKILL.md +0 -0
- /package/plugins/{devflow-core-skills → devflow-typescript}/skills/typescript/references/violations.md +0 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# Python Violation Examples
|
|
2
|
+
|
|
3
|
+
Extended violation patterns for Python reviews. Reference from main SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Type Safety Violations
|
|
6
|
+
|
|
7
|
+
### Missing Type Hints
|
|
8
|
+
|
|
9
|
+
```python
|
|
10
|
+
# VIOLATION: No type annotations
|
|
11
|
+
def process(data, config):
|
|
12
|
+
result = transform(data)
|
|
13
|
+
return result
|
|
14
|
+
|
|
15
|
+
# VIOLATION: Partial annotations (inconsistent)
|
|
16
|
+
def save(user: User, db): # db missing type
|
|
17
|
+
return db.insert(user)
|
|
18
|
+
|
|
19
|
+
# VIOLATION: Missing return type
|
|
20
|
+
def calculate_total(items: list[Item]):
|
|
21
|
+
return sum(item.price for item in items)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Bare Except Clauses
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# VIOLATION: Catches everything including SystemExit and KeyboardInterrupt
|
|
28
|
+
try:
|
|
29
|
+
process_data()
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# VIOLATION: Catches too broadly and silences
|
|
34
|
+
try:
|
|
35
|
+
user = fetch_user(user_id)
|
|
36
|
+
except Exception:
|
|
37
|
+
user = None # Hides real errors (network, auth, parsing)
|
|
38
|
+
|
|
39
|
+
# VIOLATION: Bare except with logging but no re-raise
|
|
40
|
+
try:
|
|
41
|
+
critical_operation()
|
|
42
|
+
except:
|
|
43
|
+
logger.error("Something failed")
|
|
44
|
+
# Swallows the error — caller never knows
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Data Modeling Violations
|
|
48
|
+
|
|
49
|
+
### Raw Dicts Instead of Dataclasses
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# VIOLATION: Untyped dict — no IDE support, no validation
|
|
53
|
+
user = {
|
|
54
|
+
"name": "Alice",
|
|
55
|
+
"email": "alice@example.com",
|
|
56
|
+
"age": 30,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# VIOLATION: Accessing dict keys without safety
|
|
60
|
+
def get_display_name(user: dict) -> str:
|
|
61
|
+
return f"{user['first_name']} {user['last_name']}" # KeyError risk
|
|
62
|
+
|
|
63
|
+
# VIOLATION: Nested untyped dicts
|
|
64
|
+
config = {
|
|
65
|
+
"database": {
|
|
66
|
+
"host": "localhost",
|
|
67
|
+
"port": 5432,
|
|
68
|
+
},
|
|
69
|
+
"cache": {
|
|
70
|
+
"ttl": 300,
|
|
71
|
+
},
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Mutable Default Arguments
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# VIOLATION: Mutable default shared across calls
|
|
79
|
+
def add_item(item: str, items: list[str] = []) -> list[str]:
|
|
80
|
+
items.append(item)
|
|
81
|
+
return items
|
|
82
|
+
|
|
83
|
+
# VIOLATION: Dict default mutated in place
|
|
84
|
+
def register(name: str, registry: dict[str, bool] = {}) -> None:
|
|
85
|
+
registry[name] = True
|
|
86
|
+
|
|
87
|
+
# VIOLATION: Set default
|
|
88
|
+
def collect(value: int, seen: set[int] = set()) -> set[int]:
|
|
89
|
+
seen.add(value)
|
|
90
|
+
return seen
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## String Formatting Violations
|
|
94
|
+
|
|
95
|
+
### Percent Formatting
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# VIOLATION: Old-style % formatting
|
|
99
|
+
message = "Hello %s, you have %d messages" % (name, count)
|
|
100
|
+
|
|
101
|
+
# VIOLATION: % formatting with dict — hard to read, error-prone
|
|
102
|
+
log = "%(timestamp)s - %(level)s - %(message)s" % log_data
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### String Concatenation in Loops
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
# VIOLATION: O(n^2) string building
|
|
109
|
+
result = ""
|
|
110
|
+
for line in lines:
|
|
111
|
+
result += line + "\n"
|
|
112
|
+
|
|
113
|
+
# CORRECT: Use join
|
|
114
|
+
result = "\n".join(lines)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Global State Violations
|
|
118
|
+
|
|
119
|
+
### Module-Level Mutable State
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
# VIOLATION: Global mutable state
|
|
123
|
+
_cache = {}
|
|
124
|
+
_connections = []
|
|
125
|
+
|
|
126
|
+
def get_cached(key: str) -> Any:
|
|
127
|
+
return _cache.get(key)
|
|
128
|
+
|
|
129
|
+
def add_connection(conn: Connection) -> None:
|
|
130
|
+
_connections.append(conn)
|
|
131
|
+
|
|
132
|
+
# VIOLATION: Global variable modified by functions
|
|
133
|
+
current_user = None
|
|
134
|
+
|
|
135
|
+
def login(username: str) -> None:
|
|
136
|
+
global current_user
|
|
137
|
+
current_user = authenticate(username)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Singleton via Module Import
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
# VIOLATION: Hard-to-test singleton
|
|
144
|
+
# db.py
|
|
145
|
+
connection = create_connection(os.environ["DATABASE_URL"])
|
|
146
|
+
|
|
147
|
+
# service.py
|
|
148
|
+
from db import connection # Cannot mock or swap for tests
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Import Violations
|
|
152
|
+
|
|
153
|
+
### Wildcard Imports
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
# VIOLATION: Pollutes namespace, hides dependencies
|
|
157
|
+
from os.path import *
|
|
158
|
+
from utils import *
|
|
159
|
+
|
|
160
|
+
# VIOLATION: Star import in __init__.py
|
|
161
|
+
# mypackage/__init__.py
|
|
162
|
+
from .models import *
|
|
163
|
+
from .services import *
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Circular Imports
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
# VIOLATION: Circular dependency
|
|
170
|
+
# models.py
|
|
171
|
+
from services import UserService # services imports models too
|
|
172
|
+
|
|
173
|
+
# services.py
|
|
174
|
+
from models import User # Circular!
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Testing Violations
|
|
178
|
+
|
|
179
|
+
### Assert in Production Code
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
# VIOLATION: assert is stripped with -O flag
|
|
183
|
+
def withdraw(account: Account, amount: float) -> None:
|
|
184
|
+
assert amount > 0, "Amount must be positive" # Disabled in production!
|
|
185
|
+
assert account.balance >= amount, "Insufficient funds"
|
|
186
|
+
account.balance -= amount
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### No pytest Fixtures
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
# VIOLATION: Repeated setup in every test
|
|
193
|
+
def test_create_user():
|
|
194
|
+
db = Database(":memory:")
|
|
195
|
+
db.create_tables()
|
|
196
|
+
service = UserService(db)
|
|
197
|
+
# ... test logic
|
|
198
|
+
|
|
199
|
+
def test_update_user():
|
|
200
|
+
db = Database(":memory:") # Duplicated setup
|
|
201
|
+
db.create_tables()
|
|
202
|
+
service = UserService(db)
|
|
203
|
+
# ... test logic
|
|
204
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "devflow-react",
|
|
3
|
+
"description": "React framework patterns - hooks, state management, composition, performance",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "DevFlow Contributors",
|
|
6
|
+
"email": "dean@keren.dev"
|
|
7
|
+
},
|
|
8
|
+
"version": "1.3.0",
|
|
9
|
+
"homepage": "https://github.com/dean0x/devflow",
|
|
10
|
+
"repository": "https://github.com/dean0x/devflow",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react",
|
|
14
|
+
"hooks",
|
|
15
|
+
"state",
|
|
16
|
+
"components"
|
|
17
|
+
],
|
|
18
|
+
"agents": [],
|
|
19
|
+
"skills": [
|
|
20
|
+
"react"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -95,7 +95,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
95
95
|
const [user, setUser] = useState<User | null>(null);
|
|
96
96
|
const login = async (creds: Credentials) => setUser(await authApi.login(creds));
|
|
97
97
|
const logout = () => { authApi.logout(); setUser(null); };
|
|
98
|
-
return <AuthContext
|
|
98
|
+
return <AuthContext value={{ user, login, logout }}>{children}</AuthContext>;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
export function useAuth() {
|
|
@@ -429,9 +429,9 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|
|
429
429
|
};
|
|
430
430
|
|
|
431
431
|
return (
|
|
432
|
-
<AuthContext
|
|
432
|
+
<AuthContext value={{ user, login, logout, isLoading }}>
|
|
433
433
|
{children}
|
|
434
|
-
</AuthContext
|
|
434
|
+
</AuthContext>
|
|
435
435
|
);
|
|
436
436
|
}
|
|
437
437
|
|
|
@@ -590,7 +590,7 @@ function SearchInput() {
|
|
|
590
590
|
```tsx
|
|
591
591
|
// CORRECT: Track previous value for comparisons
|
|
592
592
|
function usePrevious<T>(value: T): T | undefined {
|
|
593
|
-
const ref = useRef<T>();
|
|
593
|
+
const ref = useRef<T | undefined>(undefined);
|
|
594
594
|
|
|
595
595
|
useEffect(() => {
|
|
596
596
|
ref.current = value;
|
|
@@ -5,12 +5,22 @@
|
|
|
5
5
|
"name": "DevFlow Contributors",
|
|
6
6
|
"email": "dean@keren.dev"
|
|
7
7
|
},
|
|
8
|
-
"version": "1.
|
|
8
|
+
"version": "1.3.0",
|
|
9
9
|
"homepage": "https://github.com/dean0x/devflow",
|
|
10
10
|
"repository": "https://github.com/dean0x/devflow",
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"keywords": [
|
|
13
|
-
|
|
12
|
+
"keywords": [
|
|
13
|
+
"issues",
|
|
14
|
+
"fixes",
|
|
15
|
+
"tech-debt",
|
|
16
|
+
"resolution",
|
|
17
|
+
"review"
|
|
18
|
+
],
|
|
19
|
+
"agents": [
|
|
20
|
+
"git",
|
|
21
|
+
"resolver",
|
|
22
|
+
"simplifier"
|
|
23
|
+
],
|
|
14
24
|
"skills": [
|
|
15
25
|
"implementation-patterns",
|
|
16
26
|
"security-patterns",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: security-patterns
|
|
3
|
-
description:
|
|
3
|
+
description: This skill should be used when reviewing code for injection flaws, auth bypasses, or hardcoded secrets.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
allowed-tools: Read, Grep, Glob
|
|
6
6
|
---
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "devflow-rust",
|
|
3
|
+
"description": "Rust language patterns - ownership, borrowing, error handling, type-driven design",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "DevFlow Contributors",
|
|
6
|
+
"email": "dean@keren.dev"
|
|
7
|
+
},
|
|
8
|
+
"version": "1.3.0",
|
|
9
|
+
"homepage": "https://github.com/dean0x/devflow",
|
|
10
|
+
"repository": "https://github.com/dean0x/devflow",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"rust",
|
|
14
|
+
"ownership",
|
|
15
|
+
"borrowing",
|
|
16
|
+
"type-safety"
|
|
17
|
+
],
|
|
18
|
+
"agents": [],
|
|
19
|
+
"skills": [
|
|
20
|
+
"rust"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust
|
|
3
|
+
description: This skill should be used when the user works with Rust files (.rs), asks about "ownership", "borrowing", "lifetimes", "Result/Option", "traits", or discusses memory safety and type-driven design. Provides patterns for ownership, error handling, type system usage, and safe concurrency.
|
|
4
|
+
user-invocable: false
|
|
5
|
+
allowed-tools: Read, Grep, Glob
|
|
6
|
+
activation:
|
|
7
|
+
file-patterns:
|
|
8
|
+
- "**/*.rs"
|
|
9
|
+
exclude:
|
|
10
|
+
- "**/target/**"
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Rust Patterns
|
|
14
|
+
|
|
15
|
+
Reference for Rust-specific patterns, ownership model, and type-driven design.
|
|
16
|
+
|
|
17
|
+
## Iron Law
|
|
18
|
+
|
|
19
|
+
> **MAKE ILLEGAL STATES UNREPRESENTABLE**
|
|
20
|
+
>
|
|
21
|
+
> Encode invariants in the type system. If a function can fail, return `Result`. If a value
|
|
22
|
+
> might be absent, return `Option`. If a state transition is invalid, make it uncompilable.
|
|
23
|
+
> Runtime checks are a fallback, not a strategy.
|
|
24
|
+
|
|
25
|
+
## When This Skill Activates
|
|
26
|
+
|
|
27
|
+
- Working with Rust codebases
|
|
28
|
+
- Designing type-safe APIs
|
|
29
|
+
- Managing ownership and borrowing
|
|
30
|
+
- Implementing error handling
|
|
31
|
+
- Writing concurrent code
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Ownership & Borrowing
|
|
36
|
+
|
|
37
|
+
### Prefer Borrowing Over Cloning
|
|
38
|
+
|
|
39
|
+
```rust
|
|
40
|
+
// BAD: fn process(data: String) — takes ownership unnecessarily
|
|
41
|
+
// GOOD: fn process(data: &str) — borrows, caller keeps ownership
|
|
42
|
+
|
|
43
|
+
fn process(data: &str) -> usize {
|
|
44
|
+
data.len()
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Lifetime Annotations When Needed
|
|
49
|
+
|
|
50
|
+
```rust
|
|
51
|
+
// Return reference tied to input lifetime
|
|
52
|
+
fn first_word(s: &str) -> &str {
|
|
53
|
+
s.split_whitespace().next().unwrap_or("")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Explicit when compiler can't infer
|
|
57
|
+
struct Excerpt<'a> {
|
|
58
|
+
text: &'a str,
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Error Handling
|
|
65
|
+
|
|
66
|
+
### Use Result and the ? Operator
|
|
67
|
+
|
|
68
|
+
```rust
|
|
69
|
+
use std::fs;
|
|
70
|
+
use std::io;
|
|
71
|
+
|
|
72
|
+
fn read_config(path: &str) -> Result<Config, AppError> {
|
|
73
|
+
let content = fs::read_to_string(path)
|
|
74
|
+
.map_err(|e| AppError::Io { path: path.into(), source: e })?;
|
|
75
|
+
let config: Config = toml::from_str(&content)
|
|
76
|
+
.map_err(|e| AppError::Parse { source: e })?;
|
|
77
|
+
Ok(config)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Custom Error Types with thiserror
|
|
82
|
+
|
|
83
|
+
```rust
|
|
84
|
+
use thiserror::Error;
|
|
85
|
+
|
|
86
|
+
#[derive(Error, Debug)]
|
|
87
|
+
pub enum AppError {
|
|
88
|
+
#[error("IO error reading {path}")]
|
|
89
|
+
Io { path: String, #[source] source: io::Error },
|
|
90
|
+
#[error("parse error")]
|
|
91
|
+
Parse { #[from] source: toml::de::Error },
|
|
92
|
+
#[error("{entity} with id {id} not found")]
|
|
93
|
+
NotFound { entity: String, id: String },
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Type System
|
|
100
|
+
|
|
101
|
+
### Newtype Pattern
|
|
102
|
+
|
|
103
|
+
```rust
|
|
104
|
+
// Prevent mixing up IDs
|
|
105
|
+
struct UserId(String);
|
|
106
|
+
struct OrderId(String);
|
|
107
|
+
|
|
108
|
+
fn get_order(user_id: &UserId, order_id: &OrderId) -> Result<Order, AppError> {
|
|
109
|
+
// Can't accidentally swap parameters
|
|
110
|
+
todo!()
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Enums for State Machines
|
|
115
|
+
|
|
116
|
+
```rust
|
|
117
|
+
enum Connection {
|
|
118
|
+
Disconnected,
|
|
119
|
+
Connecting { attempt: u32 },
|
|
120
|
+
Connected { session: Session },
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Each state carries only its relevant data
|
|
124
|
+
// Invalid transitions are uncompilable
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Patterns
|
|
130
|
+
|
|
131
|
+
### Builder Pattern
|
|
132
|
+
|
|
133
|
+
```rust
|
|
134
|
+
pub struct ServerBuilder {
|
|
135
|
+
port: u16,
|
|
136
|
+
host: String,
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
impl ServerBuilder {
|
|
140
|
+
pub fn new() -> Self { Self { port: 8080, host: "localhost".into() } }
|
|
141
|
+
pub fn port(mut self, port: u16) -> Self { self.port = port; self }
|
|
142
|
+
pub fn host(mut self, host: impl Into<String>) -> Self { self.host = host.into(); self }
|
|
143
|
+
pub fn build(self) -> Server { Server { port: self.port, host: self.host } }
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Iterator Chains Over Loops
|
|
148
|
+
|
|
149
|
+
```rust
|
|
150
|
+
// BAD: manual loop with push
|
|
151
|
+
// GOOD:
|
|
152
|
+
let active_names: Vec<&str> = users.iter()
|
|
153
|
+
.filter(|u| u.is_active)
|
|
154
|
+
.map(|u| u.name.as_str())
|
|
155
|
+
.collect();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Anti-Patterns
|
|
161
|
+
|
|
162
|
+
| Pattern | Bad | Good |
|
|
163
|
+
|---------|-----|------|
|
|
164
|
+
| Unwrap in library | `.unwrap()` | `?` operator or `.ok_or()` |
|
|
165
|
+
| Clone to satisfy borrow checker | `.clone()` everywhere | Restructure ownership |
|
|
166
|
+
| String for everything | `HashMap<String, String>` | Typed structs and enums |
|
|
167
|
+
| Ignoring Result | `let _ = write(...)` | Handle or propagate error |
|
|
168
|
+
| Mutex<Vec> for message passing | Shared mutable state | Channels (`mpsc`) |
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Extended References
|
|
173
|
+
|
|
174
|
+
For additional patterns and examples:
|
|
175
|
+
- `references/violations.md` - Common Rust violations
|
|
176
|
+
- `references/patterns.md` - Extended Rust patterns
|
|
177
|
+
- `references/detection.md` - Detection patterns for Rust issues
|
|
178
|
+
- `references/ownership.md` - Advanced ownership and lifetime patterns
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Checklist
|
|
183
|
+
|
|
184
|
+
- [ ] No `.unwrap()` in library/application code (ok in tests)
|
|
185
|
+
- [ ] Custom error types with `thiserror`
|
|
186
|
+
- [ ] `?` operator for error propagation
|
|
187
|
+
- [ ] Borrow instead of clone where possible
|
|
188
|
+
- [ ] Newtype pattern for type-safe IDs
|
|
189
|
+
- [ ] Enums for state machines
|
|
190
|
+
- [ ] Iterator chains over manual loops
|
|
191
|
+
- [ ] `#[must_use]` on Result-returning functions
|
|
192
|
+
- [ ] No `unsafe` without safety comment
|
|
193
|
+
- [ ] Clippy clean (`cargo clippy -- -D warnings`)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Rust Detection Patterns
|
|
2
|
+
|
|
3
|
+
Grep and regex patterns for finding common Rust issues. Use with `Grep` tool.
|
|
4
|
+
|
|
5
|
+
## Unwrap and Expect
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Find .unwrap() calls (exclude tests)
|
|
9
|
+
grep -rn '\.unwrap()' --include='*.rs' --exclude-dir=tests --exclude='*_test.rs'
|
|
10
|
+
|
|
11
|
+
# Find .expect() without descriptive message
|
|
12
|
+
grep -rn '\.expect("")' --include='*.rs'
|
|
13
|
+
|
|
14
|
+
# Find unwrap_or_default hiding errors
|
|
15
|
+
grep -rn '\.unwrap_or_default()' --include='*.rs'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Pattern**: `\.unwrap\(\)` — matches any `.unwrap()` call
|
|
19
|
+
**Pattern**: `\.expect\("` — matches `.expect("` to review message quality
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Clone Abuse
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Find .clone() calls — review each for necessity
|
|
27
|
+
grep -rn '\.clone()' --include='*.rs'
|
|
28
|
+
|
|
29
|
+
# Find clone in loop bodies (likely hot-path waste)
|
|
30
|
+
grep -rn -A2 'for.*in' --include='*.rs' | grep '\.clone()'
|
|
31
|
+
|
|
32
|
+
# Find to_string() where &str would work
|
|
33
|
+
grep -rn '\.to_string()' --include='*.rs'
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Pattern**: `\.clone\(\)` — all clone calls for manual review
|
|
37
|
+
**Pattern**: `\.to_owned\(\)` — ownership transfer that may be unnecessary
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Unsafe Blocks
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Find all unsafe blocks
|
|
45
|
+
grep -rn 'unsafe\s*{' --include='*.rs'
|
|
46
|
+
|
|
47
|
+
# Find unsafe without SAFETY comment
|
|
48
|
+
grep -rn -B2 'unsafe\s*{' --include='*.rs' | grep -v 'SAFETY'
|
|
49
|
+
|
|
50
|
+
# Find unsafe functions
|
|
51
|
+
grep -rn 'unsafe fn' --include='*.rs'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Pattern**: `unsafe\s*\{` — unsafe blocks
|
|
55
|
+
**Pattern**: `unsafe fn` — unsafe function declarations
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Incomplete Code
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Find todo! and unimplemented! macros
|
|
63
|
+
grep -rn 'todo!\|unimplemented!' --include='*.rs'
|
|
64
|
+
|
|
65
|
+
# Find unreachable! that may hide bugs
|
|
66
|
+
grep -rn 'unreachable!' --include='*.rs'
|
|
67
|
+
|
|
68
|
+
# Find panic! in non-test code
|
|
69
|
+
grep -rn 'panic!' --include='*.rs' --exclude-dir=tests --exclude='*_test.rs'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**Pattern**: `todo!\(\)` — placeholder code
|
|
73
|
+
**Pattern**: `unimplemented!\(\)` — unfinished implementations
|
|
74
|
+
**Pattern**: `panic!\(` — explicit panics outside tests
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Error Handling Issues
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Find ignored Results (let _ = expr that returns Result)
|
|
82
|
+
grep -rn 'let _ =' --include='*.rs'
|
|
83
|
+
|
|
84
|
+
# Find empty match arms that may swallow errors
|
|
85
|
+
grep -rn '=> {}' --include='*.rs'
|
|
86
|
+
|
|
87
|
+
# Find catch-all match arms hiding missing cases
|
|
88
|
+
grep -rn '_ =>' --include='*.rs'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**Pattern**: `let _ =` — potentially ignored Result or important value
|
|
92
|
+
**Pattern**: `=> \{\}` — empty match arm (may swallow error)
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Concurrency Red Flags
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Find static mut (almost always wrong)
|
|
100
|
+
grep -rn 'static mut' --include='*.rs'
|
|
101
|
+
|
|
102
|
+
# Find blocking calls in async functions
|
|
103
|
+
grep -rn 'std::fs::' --include='*.rs' | grep -v 'test'
|
|
104
|
+
grep -rn 'std::thread::sleep' --include='*.rs'
|
|
105
|
+
|
|
106
|
+
# Find Mutex without Arc in multi-threaded context
|
|
107
|
+
grep -rn 'Mutex::new' --include='*.rs'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Pattern**: `static mut` — mutable global state (data race risk)
|
|
111
|
+
**Pattern**: `std::fs::` — blocking I/O that may appear in async context
|
|
112
|
+
**Pattern**: `std::thread::sleep` — blocking sleep (use `tokio::time::sleep` in async)
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Clippy Lints
|
|
117
|
+
|
|
118
|
+
Run Clippy for automated detection of many patterns above:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cargo clippy -- -D warnings
|
|
122
|
+
cargo clippy -- -W clippy::pedantic
|
|
123
|
+
cargo clippy -- -W clippy::nursery
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Key Clippy lints that catch issues:
|
|
127
|
+
- `clippy::unwrap_used` — flags unwrap calls
|
|
128
|
+
- `clippy::clone_on_ref_ptr` — unnecessary Arc/Rc clone
|
|
129
|
+
- `clippy::needless_pass_by_value` — should borrow instead
|
|
130
|
+
- `clippy::missing_errors_doc` — public Result fn without doc
|
|
131
|
+
- `clippy::wildcard_enum_match_arm` — catch-all hiding cases
|