@moon791017/neo-skills 1.0.33 → 1.0.34
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/GEMINI.md +2 -0
- package/README.md +6 -3
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/skills/neo-rust/SKILL.md +44 -0
- package/skills/neo-rust/reference/anti-patterns.md +358 -0
- package/skills/neo-rust/reference/coding-style.md +467 -0
- package/skills/neo-rust/reference/patterns.md +789 -0
package/GEMINI.md
CHANGED
|
@@ -113,3 +113,5 @@ When interacting with this codebase or using the extension, the agent follows th
|
|
|
113
113
|
* **JavaScript 現代語法專家:** 跨版本 JavaScript 專家 (ES6-ES2025+),專注於現代化語法、模組系統與高效能開發模式。
|
|
114
114
|
|
|
115
115
|
* **Vue 現代開發專家:** 專注於 Vue 3 Composition API (`<script setup>`)、Pinia 狀態管理與 Vue Router 4,嚴格遵循官方 Style Guide 與最佳實踐。
|
|
116
|
+
|
|
117
|
+
* **Rust 專家 (`skills/neo-rust`)**: 用於開發、重構或審查 Rust 應用程式的專家技能,涵蓋 ownership、borrowing、Result/Option 與現代 Rust 設計模式。
|
package/README.md
CHANGED
|
@@ -60,13 +60,16 @@
|
|
|
60
60
|
### 9. Vue 開發專家
|
|
61
61
|
* **Vue 3 現代開發專家 (`skills/neo-vue`)**:專注於 Vue 3 Composition API (`<script setup>`)、Pinia 狀態管理與 Vue Router 4。嚴格遵循官方 Style Guide 與最佳實踐,並提供反模式 (Anti-Patterns) 的避坑指引。
|
|
62
62
|
|
|
63
|
-
### 10.
|
|
63
|
+
### 10. Rust 開發專家
|
|
64
|
+
* **Rust 專家 (`skills/neo-rust`)**:用於開發、重構或審查 Rust 應用程式的專家技能,涵蓋 ownership、borrowing、Result/Option 與現代 Rust 設計模式。
|
|
65
|
+
|
|
66
|
+
### 11. 需求釐清助手
|
|
64
67
|
* **需求釐清**:系統化引導用戶釐清模糊需求,並將其轉化為結構化的規格文件(背景、功能、約束、驗收標準)。
|
|
65
68
|
|
|
66
|
-
###
|
|
69
|
+
### 12. AI 開發流程健檢
|
|
67
70
|
* **AI 助手開發治理 (`skills/neo-agent-harness`)**:檢查專案規則、測試、CI、審查流程與安全防護是否足夠清楚,協助 AI 助手更穩定、更安全地參與開發。
|
|
68
71
|
|
|
69
|
-
###
|
|
72
|
+
### 13. 安全守衛 (Security Guard)
|
|
70
73
|
* **主動防護 (`secret-guard.ts`)**:作為 CLI 的中介軟體 (Hook),自動攔截並掃描所有工具執行的參數。若偵測到敏感資訊(如環境設定檔、私鑰、雲端憑證等)將強制阻擋執行,防止機密外洩。
|
|
71
74
|
|
|
72
75
|
## 📂 系統架構
|
package/gemini-extension.json
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: neo-rust
|
|
3
|
+
description: 用於開發、重構或審查 Rust 應用程式的專家技能。涵蓋 ownership、borrowing、Result/Option 與現代 Rust 設計模式。當使用者要求撰寫 Rust 程式碼、進行 Code Review 或討論 Rust 架構時使用。
|
|
4
|
+
metadata:
|
|
5
|
+
pattern: tool-wrapper, reviewer
|
|
6
|
+
domain: rust
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Neo Rust Expert
|
|
10
|
+
|
|
11
|
+
You are an expert Rust developer. Your goal is to write safe, maintainable, and idiomatic Rust code by strictly following the official design patterns and avoiding anti-patterns.
|
|
12
|
+
|
|
13
|
+
## Core Directives
|
|
14
|
+
|
|
15
|
+
Before writing or reviewing any Rust code, you MUST follow the "Perceive-Reason-Act" loop:
|
|
16
|
+
|
|
17
|
+
1. **Perceive**: Understand the user's intent. Is it a new feature, a refactor, or a code review?
|
|
18
|
+
2. **Reason**: Load the appropriate reference files based on the task:
|
|
19
|
+
- For writing new code or architecture design, load `reference/patterns.md` and `reference/coding-style.md`.
|
|
20
|
+
- For code review or debugging, load `reference/anti-patterns.md` to spot common mistakes.
|
|
21
|
+
3. **Act**: Execute the task adhering strictly to the loaded guidelines.
|
|
22
|
+
|
|
23
|
+
## When Writing Code
|
|
24
|
+
- Prioritize Borrowing over Ownership where applicable (`&str` instead of `String`).
|
|
25
|
+
- Handle errors gracefully using `Result<T, E>`. Never use `.unwrap()` or `panic!()` in library or production code.
|
|
26
|
+
- Represent "no value" with `Option<T>`, never with magic values like empty strings or `-1`.
|
|
27
|
+
- Use the Type System to prevent invalid states (e.g., Typestate, Newtype, Smart Constructors).
|
|
28
|
+
- Ensure resource cleanup using RAII/Drop.
|
|
29
|
+
- Prefer explicit composition over shared mutable state. Default to single ownership.
|
|
30
|
+
|
|
31
|
+
## When Reviewing Code
|
|
32
|
+
1. Load `reference/anti-patterns.md`.
|
|
33
|
+
2. Check for unnecessary `.clone()`, excessive use of `String`, and improper error handling.
|
|
34
|
+
3. Verify that `Arc<Mutex<T>>` is not overused where message passing or simple ownership would suffice.
|
|
35
|
+
4. Check naming conventions against `reference/coding-style.md`.
|
|
36
|
+
5. Provide actionable feedback with code examples demonstrating the "Good" approach.
|
|
37
|
+
|
|
38
|
+
## Tools & Formatting
|
|
39
|
+
Always recommend standard Rust tooling: `cargo fmt`, `cargo clippy`, and `cargo check`.
|
|
40
|
+
|
|
41
|
+
## Official Resources
|
|
42
|
+
- **Rust Official Website**: https://www.rust-lang.org/
|
|
43
|
+
- **Rust Documentation**: https://doc.rust-lang.org/
|
|
44
|
+
- **The Rust Programming Language (The Book)**: https://doc.rust-lang.org/book/
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# 3. Anti-pattern:不好作法
|
|
2
|
+
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## Anti-pattern 1:到處 `.clone()` 逃避 borrow checker
|
|
6
|
+
|
|
7
|
+
### 不好
|
|
8
|
+
|
|
9
|
+
```rust
|
|
10
|
+
fn process(name: String) {
|
|
11
|
+
println!("{name}");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
fn main() {
|
|
15
|
+
let name = String::from("Alice");
|
|
16
|
+
|
|
17
|
+
process(name.clone());
|
|
18
|
+
process(name.clone());
|
|
19
|
+
process(name.clone());
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### 好
|
|
24
|
+
|
|
25
|
+
```rust
|
|
26
|
+
fn process(name: &str) {
|
|
27
|
+
println!("{name}");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn main() {
|
|
31
|
+
let name = String::from("Alice");
|
|
32
|
+
|
|
33
|
+
process(&name);
|
|
34
|
+
process(&name);
|
|
35
|
+
process(&name);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 原則
|
|
40
|
+
|
|
41
|
+
clone 不是不能用,但要知道為什麼 clone。
|
|
42
|
+
如果只是讀取,先改成 borrow。
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Anti-pattern 2:過度使用 `String`
|
|
47
|
+
|
|
48
|
+
### 不好
|
|
49
|
+
|
|
50
|
+
```rust
|
|
51
|
+
fn is_admin(role: String) -> bool {
|
|
52
|
+
role == "admin"
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 好
|
|
57
|
+
|
|
58
|
+
```rust
|
|
59
|
+
fn is_admin(role: &str) -> bool {
|
|
60
|
+
role == "admin"
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 原則
|
|
65
|
+
|
|
66
|
+
建立 ownership 才用 `String`,讀取文字優先 `&str`。
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Anti-pattern 3:用 `bool` 表達複雜狀態
|
|
71
|
+
|
|
72
|
+
### 不好
|
|
73
|
+
|
|
74
|
+
```rust
|
|
75
|
+
struct User {
|
|
76
|
+
is_active: bool,
|
|
77
|
+
is_deleted: bool,
|
|
78
|
+
is_locked: bool,
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
問題:可能出現矛盾狀態,例如 active 又 deleted。
|
|
83
|
+
|
|
84
|
+
### 好
|
|
85
|
+
|
|
86
|
+
```rust
|
|
87
|
+
enum UserStatus {
|
|
88
|
+
Active,
|
|
89
|
+
Deleted,
|
|
90
|
+
Locked,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
struct User {
|
|
94
|
+
status: UserStatus,
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Anti-pattern 4:用 `String` 表達錯誤
|
|
101
|
+
|
|
102
|
+
### 不好
|
|
103
|
+
|
|
104
|
+
```rust
|
|
105
|
+
fn parse_age(input: &str) -> Result<u8, String> {
|
|
106
|
+
input.parse::<u8>().map_err(|_| "invalid age".to_string())
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
短程式可以,但 library 或大型系統不建議只丟字串。
|
|
111
|
+
|
|
112
|
+
### 好
|
|
113
|
+
|
|
114
|
+
```rust
|
|
115
|
+
#[derive(Debug)]
|
|
116
|
+
enum ParseAgeError {
|
|
117
|
+
InvalidNumber,
|
|
118
|
+
TooLarge,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
fn parse_age(input: &str) -> Result<u8, ParseAgeError> {
|
|
122
|
+
let age = input.parse::<u8>().map_err(|_| ParseAgeError::InvalidNumber)?;
|
|
123
|
+
|
|
124
|
+
if age > 120 {
|
|
125
|
+
return Err(ParseAgeError::TooLarge);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Ok(age)
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 原則
|
|
133
|
+
|
|
134
|
+
錯誤要可分類、可測試、可處理。
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Anti-pattern 5:library 內部亂 `panic!`
|
|
139
|
+
|
|
140
|
+
### 不好
|
|
141
|
+
|
|
142
|
+
```rust
|
|
143
|
+
pub fn divide(a: i32, b: i32) -> i32 {
|
|
144
|
+
if b == 0 {
|
|
145
|
+
panic!("divide by zero");
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
a / b
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 好
|
|
153
|
+
|
|
154
|
+
```rust
|
|
155
|
+
#[derive(Debug)]
|
|
156
|
+
pub enum DivideError {
|
|
157
|
+
DivideByZero,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
pub fn divide(a: i32, b: i32) -> Result<i32, DivideError> {
|
|
161
|
+
if b == 0 {
|
|
162
|
+
return Err(DivideError::DivideByZero);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
Ok(a / b)
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 原則
|
|
170
|
+
|
|
171
|
+
除非是不可恢復的程式錯誤,否則回傳 `Result`。
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Anti-pattern 6:過度 Trait 化
|
|
176
|
+
|
|
177
|
+
### 不好
|
|
178
|
+
|
|
179
|
+
```rust
|
|
180
|
+
trait UserNameProvider {
|
|
181
|
+
fn user_name(&self) -> &str;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
struct User {
|
|
185
|
+
name: String,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
impl UserNameProvider for User {
|
|
189
|
+
fn user_name(&self) -> &str {
|
|
190
|
+
&self.name
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
問題:只有一個 struct、一個方法、沒有替換需求時,trait 只是噪音。
|
|
196
|
+
|
|
197
|
+
### 好
|
|
198
|
+
|
|
199
|
+
```rust
|
|
200
|
+
struct User {
|
|
201
|
+
name: String,
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
impl User {
|
|
205
|
+
fn name(&self) -> &str {
|
|
206
|
+
&self.name
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 原則
|
|
212
|
+
|
|
213
|
+
先用 concrete type。真的需要抽象再抽 trait。
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Anti-pattern 7:公開欄位破壞 invariant
|
|
218
|
+
|
|
219
|
+
### 不好
|
|
220
|
+
|
|
221
|
+
```rust
|
|
222
|
+
pub struct Account {
|
|
223
|
+
pub balance: i64,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
fn main() {
|
|
227
|
+
let mut account = Account { balance: 100 };
|
|
228
|
+
account.balance = -999;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### 好
|
|
233
|
+
|
|
234
|
+
```rust
|
|
235
|
+
pub struct Account {
|
|
236
|
+
balance: i64,
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
impl Account {
|
|
240
|
+
pub fn new(balance: i64) -> Result<Self, String> {
|
|
241
|
+
if balance < 0 {
|
|
242
|
+
return Err("balance cannot be negative".to_string());
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
Ok(Self { balance })
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
pub fn balance(&self) -> i64 {
|
|
249
|
+
self.balance
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
pub fn deposit(&mut self, amount: i64) -> Result<(), String> {
|
|
253
|
+
if amount <= 0 {
|
|
254
|
+
return Err("amount must be positive".to_string());
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
self.balance += amount;
|
|
258
|
+
Ok(())
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Anti-pattern 8:`Arc<Mutex<T>>` 到處傳
|
|
266
|
+
|
|
267
|
+
### 不好
|
|
268
|
+
|
|
269
|
+
```rust
|
|
270
|
+
use std::sync::{Arc, Mutex};
|
|
271
|
+
|
|
272
|
+
struct AppState {
|
|
273
|
+
users: Arc<Mutex<Vec<String>>>,
|
|
274
|
+
logs: Arc<Mutex<Vec<String>>>,
|
|
275
|
+
configs: Arc<Mutex<Vec<String>>>,
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
問題:鎖太多、責任不清楚、容易死鎖、測試困難。
|
|
280
|
+
|
|
281
|
+
### 好
|
|
282
|
+
|
|
283
|
+
```rust
|
|
284
|
+
struct UserService {
|
|
285
|
+
users: Vec<String>,
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
impl UserService {
|
|
289
|
+
fn create_user(&mut self, name: String) {
|
|
290
|
+
self.users.push(name);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 原則
|
|
296
|
+
|
|
297
|
+
能單一 ownership 就不要共享。
|
|
298
|
+
需要跨 thread 再考慮 `Arc<Mutex<T>>`。
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## Anti-pattern 9:在 async 中持有 lock 跨 `.await`
|
|
303
|
+
|
|
304
|
+
### 不好
|
|
305
|
+
|
|
306
|
+
```rust
|
|
307
|
+
// 概念示意
|
|
308
|
+
let mut guard = state.lock().await;
|
|
309
|
+
do_async_work().await;
|
|
310
|
+
guard.push(1);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
問題:lock 持有時間太長,容易造成效能問題或 deadlock-like 行為。
|
|
314
|
+
|
|
315
|
+
### 好
|
|
316
|
+
|
|
317
|
+
```rust
|
|
318
|
+
let data = {
|
|
319
|
+
let mut guard = state.lock().await;
|
|
320
|
+
guard.push(1);
|
|
321
|
+
guard.clone()
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
do_async_work(data).await;
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### 原則
|
|
328
|
+
|
|
329
|
+
鎖內只做最短、同步、必要的事情。
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## Anti-pattern 10:濫用 `unsafe`
|
|
334
|
+
|
|
335
|
+
### 不好
|
|
336
|
+
|
|
337
|
+
```rust
|
|
338
|
+
unsafe {
|
|
339
|
+
// 為了繞過 borrow checker 亂用 raw pointer
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### 好
|
|
344
|
+
|
|
345
|
+
先問:
|
|
346
|
+
|
|
347
|
+
1. 能不能用 ownership 改設計?
|
|
348
|
+
2. 能不能用 `Rc` / `Arc`?
|
|
349
|
+
3. 能不能用 `RefCell` / `Mutex`?
|
|
350
|
+
4. 能不能拆資料結構?
|
|
351
|
+
5. 真的需要 FFI、SIMD、底層記憶體操作嗎?
|
|
352
|
+
|
|
353
|
+
### 原則
|
|
354
|
+
|
|
355
|
+
`unsafe` 不是效能開關,是你接手編譯器無法保證的安全責任。
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|