@jmylchreest/aide-plugin 0.0.37 → 0.0.39
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/package.json +1 -1
- package/skills/code-search/SKILL.md +29 -1
- package/skills/debug/SKILL.md +40 -20
- package/skills/forget/SKILL.md +224 -0
- package/skills/implement/SKILL.md +10 -1
- package/skills/perf/SKILL.md +56 -32
- package/skills/review/SKILL.md +50 -18
- package/skills/test/SKILL.md +38 -22
- package/src/core/context-guard.ts +214 -0
- package/src/opencode/index.ts +3 -3
package/package.json
CHANGED
|
@@ -60,7 +60,21 @@ What functions are in src/auth.ts?
|
|
|
60
60
|
→ Returns: all functions, classes, types in that file
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
### 4.
|
|
63
|
+
### 4. File Outline (`mcp__plugin_aide_aide__code_outline`)
|
|
64
|
+
|
|
65
|
+
Get a collapsed structural outline of a file — signatures preserved, bodies replaced with `{ ... }`.
|
|
66
|
+
Uses ~5-15% of the tokens of the full file. **Use this before reading a file** to understand its
|
|
67
|
+
structure, then use `Read` with offset/limit for specific sections.
|
|
68
|
+
|
|
69
|
+
**Example usage:**
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Outline src/auth.ts
|
|
73
|
+
→ Uses code_outline tool
|
|
74
|
+
→ Returns: collapsed view with signatures, line ranges, bodies collapsed
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 5. Check Index Status (`mcp__plugin_aide_aide__code_stats`)
|
|
64
78
|
|
|
65
79
|
Check if the codebase has been indexed.
|
|
66
80
|
|
|
@@ -108,6 +122,20 @@ Is the code indexed?
|
|
|
108
122
|
1. Use `code_references` with symbol "authenticateUser"
|
|
109
123
|
2. Show all call sites grouped by file
|
|
110
124
|
|
|
125
|
+
## What These Tools Cover
|
|
126
|
+
|
|
127
|
+
`code_search` and `code_references` work from the tree-sitter symbol index. They find:
|
|
128
|
+
|
|
129
|
+
- Function, method, class, interface, type definitions by name
|
|
130
|
+
- Symbol signatures (parameter types, return types)
|
|
131
|
+
- Doc comments attached to definitions
|
|
132
|
+
- Call sites for a specific symbol name (via `code_references`)
|
|
133
|
+
|
|
134
|
+
For anything else — patterns inside function bodies, method call chains, string literals,
|
|
135
|
+
SQL queries, imports, variable declarations — use **Grep**, which searches code content directly.
|
|
136
|
+
|
|
137
|
+
In short: `code_search` finds _where things are defined_; Grep finds _patterns in code content_.
|
|
138
|
+
|
|
111
139
|
## Notes
|
|
112
140
|
|
|
113
141
|
- Code must be indexed first: `./.aide/bin/aide code index`
|
package/skills/debug/SKILL.md
CHANGED
|
@@ -18,6 +18,7 @@ Systematic approach to identifying and fixing bugs.
|
|
|
18
18
|
## Prerequisites
|
|
19
19
|
|
|
20
20
|
Before starting:
|
|
21
|
+
|
|
21
22
|
- Get the exact error message or unexpected behavior description
|
|
22
23
|
- Identify the entry point or trigger for the bug
|
|
23
24
|
- Note any relevant environment details (Node version, OS, etc.)
|
|
@@ -36,12 +37,14 @@ node path/to/script.js
|
|
|
36
37
|
```
|
|
37
38
|
|
|
38
39
|
Document:
|
|
40
|
+
|
|
39
41
|
- Exact error message
|
|
40
42
|
- Steps to trigger
|
|
41
43
|
- Expected vs actual behavior
|
|
42
44
|
- Is it consistent or intermittent?
|
|
43
45
|
|
|
44
46
|
**If cannot reproduce:**
|
|
47
|
+
|
|
45
48
|
- Check environment differences
|
|
46
49
|
- Look for race conditions
|
|
47
50
|
- Check for cached state
|
|
@@ -54,6 +57,9 @@ Use tools to find code related to the error:
|
|
|
54
57
|
# Search for function mentioned in stack trace
|
|
55
58
|
mcp__plugin_aide_aide__code_search query="functionName" kind="function"
|
|
56
59
|
|
|
60
|
+
# Get a structural overview of the suspect file (signatures + line ranges)
|
|
61
|
+
mcp__plugin_aide_aide__code_outline file="path/to/file.ts"
|
|
62
|
+
|
|
57
63
|
# Get symbols in suspect file
|
|
58
64
|
mcp__plugin_aide_aide__code_symbols file="path/to/file.ts"
|
|
59
65
|
|
|
@@ -65,23 +71,26 @@ Grep for "error message text"
|
|
|
65
71
|
|
|
66
72
|
Follow the code flow from entry to error:
|
|
67
73
|
|
|
68
|
-
1.
|
|
69
|
-
2.
|
|
70
|
-
3. Use `
|
|
71
|
-
|
|
74
|
+
1. Use `code_outline` on each file in the call chain to understand its structure
|
|
75
|
+
2. Use `code_references` to find callers of the failing function
|
|
76
|
+
3. Use `Read` with offset/limit to read specific functions in the execution path
|
|
77
|
+
(use line numbers from the outline)
|
|
78
|
+
4. Check type definitions with `code_search kind="interface"`
|
|
79
|
+
|
|
80
|
+
Outlines help you identify which functions matter, so you can read just those sections.
|
|
72
81
|
|
|
73
82
|
### Step 4: Form Hypotheses
|
|
74
83
|
|
|
75
84
|
Based on the error type, consider these causes:
|
|
76
85
|
|
|
77
|
-
| Symptom
|
|
78
|
-
|
|
79
|
-
| "undefined is not a function"
|
|
80
|
-
| "Cannot read property of undefined" | Missing null check, async timing issue
|
|
81
|
-
| "Type error"
|
|
82
|
-
| "Maximum call stack"
|
|
83
|
-
| "Network error"
|
|
84
|
-
| "State not updating"
|
|
86
|
+
| Symptom | Likely Causes |
|
|
87
|
+
| ----------------------------------- | -------------------------------------------------- |
|
|
88
|
+
| "undefined is not a function" | Variable is null/undefined, wrong import |
|
|
89
|
+
| "Cannot read property of undefined" | Missing null check, async timing issue |
|
|
90
|
+
| "Type error" | Type mismatch, wrong function signature |
|
|
91
|
+
| "Maximum call stack" | Infinite recursion, circular reference |
|
|
92
|
+
| "Network error" | Bad URL, CORS, timeout, server down |
|
|
93
|
+
| "State not updating" | Mutation instead of new object, missing dependency |
|
|
85
94
|
|
|
86
95
|
### Step 5: Validate Hypotheses
|
|
87
96
|
|
|
@@ -99,6 +108,7 @@ npm test -- --grep "test name"
|
|
|
99
108
|
```
|
|
100
109
|
|
|
101
110
|
**Validation checklist:**
|
|
111
|
+
|
|
102
112
|
- Check variable values at key points
|
|
103
113
|
- Verify assumptions about input data
|
|
104
114
|
- Test edge cases (null, empty, boundary values)
|
|
@@ -107,11 +117,13 @@ npm test -- --grep "test name"
|
|
|
107
117
|
### Step 6: Apply the Fix
|
|
108
118
|
|
|
109
119
|
**Rules:**
|
|
120
|
+
|
|
110
121
|
- Change only what's necessary to fix the bug
|
|
111
122
|
- Don't refactor unrelated code
|
|
112
123
|
- Match existing code patterns
|
|
113
124
|
|
|
114
125
|
**Common fixes:**
|
|
126
|
+
|
|
115
127
|
- Add null/undefined check
|
|
116
128
|
- Fix type annotation
|
|
117
129
|
- Correct async/await usage
|
|
@@ -132,24 +144,26 @@ npm test
|
|
|
132
144
|
```
|
|
133
145
|
|
|
134
146
|
**Verification criteria:**
|
|
147
|
+
|
|
135
148
|
- Original issue no longer occurs
|
|
136
149
|
- Related tests still pass
|
|
137
150
|
- No new errors introduced
|
|
138
151
|
|
|
139
152
|
## Failure Handling
|
|
140
153
|
|
|
141
|
-
| Situation
|
|
142
|
-
|
|
143
|
-
| Cannot reproduce
|
|
144
|
-
| Multiple bugs intertwined
|
|
145
|
-
| Fix causes new failures
|
|
146
|
-
| Root cause is in dependency | Check for updates, file issue, implement workaround
|
|
147
|
-
| Bug is in async code
|
|
154
|
+
| Situation | Action |
|
|
155
|
+
| --------------------------- | ---------------------------------------------------- |
|
|
156
|
+
| Cannot reproduce | Check environment, add logging to narrow down |
|
|
157
|
+
| Multiple bugs intertwined | Fix one at a time, verify after each |
|
|
158
|
+
| Fix causes new failures | Revert, analyze dependencies, try different approach |
|
|
159
|
+
| Root cause is in dependency | Check for updates, file issue, implement workaround |
|
|
160
|
+
| Bug is in async code | Add proper await, check Promise chains |
|
|
148
161
|
|
|
149
162
|
## MCP Tools
|
|
150
163
|
|
|
164
|
+
- `mcp__plugin_aide_aide__code_outline` - **Start here.** Get collapsed file skeleton to understand structure before reading
|
|
151
165
|
- `mcp__plugin_aide_aide__code_search` - Find functions, classes, types involved in the bug
|
|
152
|
-
- `mcp__plugin_aide_aide__code_symbols` -
|
|
166
|
+
- `mcp__plugin_aide_aide__code_symbols` - List all symbols in a file
|
|
153
167
|
- `mcp__plugin_aide_aide__code_references` - Find all callers of a function
|
|
154
168
|
- `mcp__plugin_aide_aide__memory_search` - Check for related past issues
|
|
155
169
|
|
|
@@ -159,24 +173,30 @@ npm test
|
|
|
159
173
|
## Debug Report: [Issue Title]
|
|
160
174
|
|
|
161
175
|
### Problem
|
|
176
|
+
|
|
162
177
|
[What was happening vs what should happen]
|
|
163
178
|
|
|
164
179
|
### Reproduction
|
|
180
|
+
|
|
165
181
|
[Steps to reproduce the issue]
|
|
166
182
|
|
|
167
183
|
### Root Cause
|
|
184
|
+
|
|
168
185
|
[Identified cause with file:line reference]
|
|
169
186
|
[Why the bug occurred]
|
|
170
187
|
|
|
171
188
|
### Fix Applied
|
|
189
|
+
|
|
172
190
|
[What was changed and why]
|
|
173
191
|
|
|
174
192
|
### Verification
|
|
193
|
+
|
|
175
194
|
- Original issue: FIXED
|
|
176
195
|
- Related tests: PASS
|
|
177
196
|
- Full suite: PASS
|
|
178
197
|
|
|
179
198
|
### Prevention
|
|
199
|
+
|
|
180
200
|
[Optional: How to prevent similar bugs]
|
|
181
201
|
```
|
|
182
202
|
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: forget
|
|
3
|
+
description: Soft-delete memories by adding/removing the forget tag, or hard-delete outdated memories
|
|
4
|
+
triggers:
|
|
5
|
+
- forget this
|
|
6
|
+
- forget that
|
|
7
|
+
- forget memory
|
|
8
|
+
- remove memory
|
|
9
|
+
- delete memory
|
|
10
|
+
- outdated memory
|
|
11
|
+
- wrong memory
|
|
12
|
+
- incorrect memory
|
|
13
|
+
- supersede memory
|
|
14
|
+
- obsolete
|
|
15
|
+
- no longer true
|
|
16
|
+
- no longer relevant
|
|
17
|
+
- not true anymore
|
|
18
|
+
- that was wrong
|
|
19
|
+
- disregard
|
|
20
|
+
allowed-tools: Bash(./.aide/bin/aide memory *)
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
# Forget
|
|
24
|
+
|
|
25
|
+
**Recommended model tier:** balanced (sonnet) - this skill performs straightforward operations
|
|
26
|
+
|
|
27
|
+
Manage outdated, incorrect, or obsolete memories by soft-deleting (tagging with `forget`) or hard-deleting them.
|
|
28
|
+
|
|
29
|
+
## Key Concepts
|
|
30
|
+
|
|
31
|
+
### Soft Delete (Preferred)
|
|
32
|
+
|
|
33
|
+
Memories tagged with `forget` are **excluded by default** from search, list, and context injection. They remain in the database and can be recovered.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
./.aide/bin/aide memory tag <MEMORY_ID> --add=forget
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Hard Delete (Permanent)
|
|
40
|
+
|
|
41
|
+
Permanently removes a memory from the database. Use when the memory is clearly wrong or contains sensitive data.
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
./.aide/bin/aide memory delete <MEMORY_ID>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Unforget (Recover)
|
|
48
|
+
|
|
49
|
+
Remove the `forget` tag to restore a soft-deleted memory.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
./.aide/bin/aide memory tag <MEMORY_ID> --remove=forget
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Workflow
|
|
56
|
+
|
|
57
|
+
When the user wants to forget, correct, or supersede a memory:
|
|
58
|
+
|
|
59
|
+
### Step 1: Find the Memory
|
|
60
|
+
|
|
61
|
+
Search for the memory to identify its ID:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# Search by content keywords
|
|
65
|
+
./.aide/bin/aide memory search "<keywords>" --full --limit=10
|
|
66
|
+
|
|
67
|
+
# If the memory might already be forgotten, include all
|
|
68
|
+
./.aide/bin/aide memory list --all
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Step 2: Confirm with User
|
|
72
|
+
|
|
73
|
+
Before deleting or forgetting, show the user what was found and confirm which memories to act on. Display the memory ID, content, and tags.
|
|
74
|
+
|
|
75
|
+
### Step 3: Apply the Appropriate Action
|
|
76
|
+
|
|
77
|
+
Choose based on the situation:
|
|
78
|
+
|
|
79
|
+
| Situation | Action | Command |
|
|
80
|
+
| ------------------------------------ | --------------------------------------- | -------------------------------------- |
|
|
81
|
+
| Memory is outdated but was once true | Soft delete (forget) | `aide memory tag <ID> --add=forget` |
|
|
82
|
+
| Memory is factually wrong | Hard delete | `aide memory delete <ID>` |
|
|
83
|
+
| Memory is resolved (issue fixed) | Soft delete + optionally add resolution | See "Superseding" below |
|
|
84
|
+
| Memory contains sensitive data | Hard delete | `aide memory delete <ID>` |
|
|
85
|
+
| Memory was accidentally forgotten | Unforget | `aide memory tag <ID> --remove=forget` |
|
|
86
|
+
|
|
87
|
+
### Step 4: Optionally Add a Replacement
|
|
88
|
+
|
|
89
|
+
If the memory is being superseded (not just deleted), add a new corrected memory **without** the `forget` tag:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# 1. Forget the old memory
|
|
93
|
+
./.aide/bin/aide memory tag <OLD_ID> --add=forget
|
|
94
|
+
|
|
95
|
+
# 2. Add the corrected memory (NO forget tag)
|
|
96
|
+
./.aide/bin/aide memory add --category=<category> --tags=<relevant,tags> "<corrected content>"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 5: Verify
|
|
100
|
+
|
|
101
|
+
Confirm the memory is no longer visible in normal searches:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Should NOT appear in normal search
|
|
105
|
+
./.aide/bin/aide memory search "<keywords>"
|
|
106
|
+
|
|
107
|
+
# Should appear with --all flag
|
|
108
|
+
./.aide/bin/aide memory list --all
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Anti-Patterns (AVOID)
|
|
112
|
+
|
|
113
|
+
### DO NOT add a new memory with the forget tag to "supersede" an old one
|
|
114
|
+
|
|
115
|
+
This is the most common mistake. Adding a new memory tagged `forget` does nothing useful:
|
|
116
|
+
|
|
117
|
+
- The new "superseding" memory is immediately hidden (because it has the `forget` tag)
|
|
118
|
+
- The original incorrect memory remains visible and active
|
|
119
|
+
|
|
120
|
+
**Wrong:**
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
# BAD - creates a hidden memory, leaves the original untouched
|
|
124
|
+
aide memory add --tags="forget,some-topic" "RESOLVED: the old issue is fixed"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Correct:**
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# GOOD - forget the original, add a visible replacement
|
|
131
|
+
aide memory tag <ORIGINAL_ID> --add=forget
|
|
132
|
+
aide memory add --tags="some-topic" "RESOLVED: the old issue is fixed"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### DO NOT guess memory IDs
|
|
136
|
+
|
|
137
|
+
Always search first to find the exact memory ID. Memory IDs are ULIDs (e.g., `01KJ3X7GMQET613WMPT7JT8GYD`).
|
|
138
|
+
|
|
139
|
+
### DO NOT forget memories without user confirmation
|
|
140
|
+
|
|
141
|
+
Always show the user what will be affected and get confirmation before acting, especially for hard deletes.
|
|
142
|
+
|
|
143
|
+
## Batch Operations
|
|
144
|
+
|
|
145
|
+
To forget multiple related memories:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Search for all related memories
|
|
149
|
+
./.aide/bin/aide memory search "<topic>" --full --limit=50
|
|
150
|
+
|
|
151
|
+
# Forget each one (after user confirmation)
|
|
152
|
+
./.aide/bin/aide memory tag <ID1> --add=forget
|
|
153
|
+
./.aide/bin/aide memory tag <ID2> --add=forget
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
To clear ALL memories (destructive, requires explicit user request):
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
./.aide/bin/aide memory clear
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Examples
|
|
163
|
+
|
|
164
|
+
### User says "that thing about ESM imports is wrong"
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# 1. Find the memory
|
|
168
|
+
./.aide/bin/aide memory search "ESM imports" --full
|
|
169
|
+
|
|
170
|
+
# 2. Show user and confirm
|
|
171
|
+
# "Found memory 01KJ... about ESM imports requiring .js extensions. Delete this?"
|
|
172
|
+
|
|
173
|
+
# 3. Soft delete
|
|
174
|
+
./.aide/bin/aide memory tag 01KJ3XVFXBFTKKH1M500N6R5 --add=forget
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### User says "we changed from JWT to sessions, update the memory"
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# 1. Find the old memory
|
|
181
|
+
./.aide/bin/aide memory search "JWT auth" --full
|
|
182
|
+
|
|
183
|
+
# 2. Forget the old one
|
|
184
|
+
./.aide/bin/aide memory tag <OLD_ID> --add=forget
|
|
185
|
+
|
|
186
|
+
# 3. Add the corrected one
|
|
187
|
+
./.aide/bin/aide memory add --category=decision --tags=auth,sessions,project:myapp "Auth strategy changed from JWT to server-side sessions with Redis store"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### User says "recover that forgotten memory about testing"
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
# 1. Find forgotten memories
|
|
194
|
+
./.aide/bin/aide memory list --all
|
|
195
|
+
|
|
196
|
+
# 2. Unforget it
|
|
197
|
+
./.aide/bin/aide memory tag <ID> --remove=forget
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Failure Handling
|
|
201
|
+
|
|
202
|
+
If `aide memory tag` fails:
|
|
203
|
+
|
|
204
|
+
1. **"memory not found"** - The ID may be wrong. Re-search with `--all` flag to include forgotten memories.
|
|
205
|
+
2. **Panic/crash** - If the tag command panics, fall back to delete + re-add:
|
|
206
|
+
```bash
|
|
207
|
+
# Workaround: get memory content, delete, re-add with forget tag
|
|
208
|
+
./.aide/bin/aide memory list --all # Find the memory content
|
|
209
|
+
./.aide/bin/aide memory delete <ID>
|
|
210
|
+
./.aide/bin/aide memory add --category=<cat> --tags=<existing-tags>,forget "<content>"
|
|
211
|
+
```
|
|
212
|
+
3. **Database locked** - Another process may hold the lock. Wait and retry, or ensure the aide daemon is running (CLI routes through gRPC when daemon is active).
|
|
213
|
+
|
|
214
|
+
## Verification
|
|
215
|
+
|
|
216
|
+
After forgetting a memory, verify:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
# Memory should NOT appear here
|
|
220
|
+
./.aide/bin/aide memory search "<term>"
|
|
221
|
+
|
|
222
|
+
# Memory SHOULD appear here (with forget tag)
|
|
223
|
+
./.aide/bin/aide memory list --all
|
|
224
|
+
```
|
|
@@ -51,10 +51,19 @@ Understand what the tests expect:
|
|
|
51
51
|
- What edge cases are covered?
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
#
|
|
54
|
+
# For large test files, get the structure first
|
|
55
|
+
mcp__plugin_aide_aide__code_outline file="path/to/feature.test.ts"
|
|
56
|
+
|
|
57
|
+
# Then read specific test sections with offset/limit
|
|
58
|
+
Read path/to/feature.test.ts offset=<start> limit=<count>
|
|
59
|
+
|
|
60
|
+
# For small test files (<100 lines), reading the full file is fine
|
|
55
61
|
Read path/to/feature.test.ts
|
|
56
62
|
```
|
|
57
63
|
|
|
64
|
+
When implementing, use `code_outline` on adjacent/related source files to understand
|
|
65
|
+
their structure before reading them fully. This preserves context for the implementation work.
|
|
66
|
+
|
|
58
67
|
### Step 3: Check Design Decisions
|
|
59
68
|
|
|
60
69
|
Use `mcp__plugin_aide_aide__decision_get` with the feature topic to review decisions from DESIGN stage.
|
package/skills/perf/SKILL.md
CHANGED
|
@@ -19,6 +19,7 @@ Systematic approach to identifying and fixing performance issues.
|
|
|
19
19
|
## Prerequisites
|
|
20
20
|
|
|
21
21
|
Before starting:
|
|
22
|
+
|
|
22
23
|
- Identify the specific operation or endpoint that is slow
|
|
23
24
|
- Understand what "fast enough" means (target latency, throughput)
|
|
24
25
|
- Ensure you can measure performance reproducibly
|
|
@@ -45,6 +46,7 @@ curl -w "@curl-format.txt" -o /dev/null -s "http://localhost:3000/api/endpoint"
|
|
|
45
46
|
```
|
|
46
47
|
|
|
47
48
|
**Record baseline metrics:**
|
|
49
|
+
|
|
48
50
|
- Execution time (p50, p95, p99 if available)
|
|
49
51
|
- Memory usage
|
|
50
52
|
- Number of operations per second
|
|
@@ -65,30 +67,42 @@ go tool pprof -http=:8080 cpu.prof
|
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
```
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
mcp__plugin_aide_aide__code_search query="map" kind="function"
|
|
70
|
+
# Get structural overview of suspect files (signatures + line ranges, not full content)
|
|
71
|
+
mcp__plugin_aide_aide__code_outline file="path/to/hotspot.ts"
|
|
71
72
|
|
|
72
|
-
# Find
|
|
73
|
-
|
|
73
|
+
# Find functions/classes in suspect area by name
|
|
74
|
+
mcp__plugin_aide_aide__code_search query="processData" kind="function"
|
|
74
75
|
|
|
75
|
-
# Find
|
|
76
|
-
|
|
76
|
+
# Find all callers of a hot function
|
|
77
|
+
mcp__plugin_aide_aide__code_references symbol="processData"
|
|
78
|
+
|
|
79
|
+
# Search for expensive patterns in code bodies (Grep is better here)
|
|
80
|
+
Grep for ".forEach(", ".map(", ".filter(" # Loop/iteration patterns
|
|
81
|
+
Grep for "SELECT", "find(", "query(" # Database queries
|
|
82
|
+
Grep for "fetch(", "axios", "http.Get" # Network calls
|
|
83
|
+
Grep for "setTimeout", "setInterval" # Timers
|
|
84
|
+
Grep for "JSON.parse", "JSON.stringify" # Serialization
|
|
77
85
|
```
|
|
78
86
|
|
|
87
|
+
Note: `code_search` finds function/class/type _definitions_ by name.
|
|
88
|
+
For patterns inside function bodies (loops, queries, call chains), use Grep.
|
|
89
|
+
|
|
90
|
+
After identifying hotspot functions via profiling and search, use `Read` with offset/limit to read
|
|
91
|
+
specific functions (use line numbers from `code_outline`).
|
|
92
|
+
|
|
79
93
|
### Step 3: Analyze Performance Patterns
|
|
80
94
|
|
|
81
95
|
Look for these common issues:
|
|
82
96
|
|
|
83
|
-
| Issue
|
|
84
|
-
|
|
85
|
-
| N+1 queries
|
|
86
|
-
| Repeated computation | Same calculation in loop
|
|
87
|
-
| Large allocations
|
|
88
|
-
| Blocking I/O
|
|
89
|
-
| Missing indexes
|
|
90
|
-
| Unnecessary work
|
|
91
|
-
| Serial execution
|
|
97
|
+
| Issue | Pattern | Solution |
|
|
98
|
+
| -------------------- | -------------------------- | --------------------- |
|
|
99
|
+
| N+1 queries | Loop containing DB call | Batch/eager load |
|
|
100
|
+
| Repeated computation | Same calculation in loop | Memoize/cache |
|
|
101
|
+
| Large allocations | Creating objects in loop | Reuse/pool objects |
|
|
102
|
+
| Blocking I/O | Sync file/network ops | Make async/concurrent |
|
|
103
|
+
| Missing indexes | Slow DB queries | Add database indexes |
|
|
104
|
+
| Unnecessary work | Processing unused data | Filter/skip early |
|
|
105
|
+
| Serial execution | Sequential independent ops | Parallelize |
|
|
92
106
|
|
|
93
107
|
### Step 4: Apply Optimizations
|
|
94
108
|
|
|
@@ -111,6 +125,7 @@ go test -bench=. -benchmem ./...
|
|
|
111
125
|
```
|
|
112
126
|
|
|
113
127
|
Compare:
|
|
128
|
+
|
|
114
129
|
- Did the metric improve?
|
|
115
130
|
- By how much (percentage)?
|
|
116
131
|
- Any negative side effects?
|
|
@@ -130,13 +145,13 @@ go test ./...
|
|
|
130
145
|
|
|
131
146
|
## Failure Handling
|
|
132
147
|
|
|
133
|
-
| Situation
|
|
134
|
-
|
|
135
|
-
| Cannot measure reliably
|
|
136
|
-
| Optimization made it slower
|
|
137
|
-
| Optimization broke tests
|
|
138
|
-
| Bottleneck is external
|
|
139
|
-
| Memory improved but CPU worse | Evaluate trade-off for use case
|
|
148
|
+
| Situation | Action |
|
|
149
|
+
| ----------------------------- | --------------------------------------------- |
|
|
150
|
+
| Cannot measure reliably | Increase sample size, reduce variance sources |
|
|
151
|
+
| Optimization made it slower | Revert, analyze why, profile more carefully |
|
|
152
|
+
| Optimization broke tests | Fix tests or revert if behavior changed |
|
|
153
|
+
| Bottleneck is external | Document, consider caching, async processing |
|
|
154
|
+
| Memory improved but CPU worse | Evaluate trade-off for use case |
|
|
140
155
|
|
|
141
156
|
## Common Optimizations
|
|
142
157
|
|
|
@@ -149,12 +164,12 @@ for (const user of users) {
|
|
|
149
164
|
}
|
|
150
165
|
|
|
151
166
|
// GOOD: Batch query
|
|
152
|
-
const userIds = users.map(u => u.id);
|
|
167
|
+
const userIds = users.map((u) => u.id);
|
|
153
168
|
const posts = await db.getPostsForUsers(userIds);
|
|
154
169
|
|
|
155
170
|
// BAD: Repeated work
|
|
156
|
-
const typeA = items.filter(x => x.type ===
|
|
157
|
-
const typeB = items.filter(x => x.type ===
|
|
171
|
+
const typeA = items.filter((x) => x.type === "a").map((x) => x.value);
|
|
172
|
+
const typeB = items.filter((x) => x.type === "b").map((x) => x.value);
|
|
158
173
|
|
|
159
174
|
// GOOD: Single pass
|
|
160
175
|
const grouped = { a: [], b: [] };
|
|
@@ -167,10 +182,7 @@ const result1 = await fetch(url1);
|
|
|
167
182
|
const result2 = await fetch(url2);
|
|
168
183
|
|
|
169
184
|
// GOOD: Parallel async
|
|
170
|
-
const [result1, result2] = await Promise.all([
|
|
171
|
-
fetch(url1),
|
|
172
|
-
fetch(url2)
|
|
173
|
-
]);
|
|
185
|
+
const [result1, result2] = await Promise.all([fetch(url1), fetch(url2)]);
|
|
174
186
|
```
|
|
175
187
|
|
|
176
188
|
### Go
|
|
@@ -225,13 +237,17 @@ SELECT * FROM posts WHERE user_id IN (?, ?, ?);
|
|
|
225
237
|
|
|
226
238
|
## MCP Tools
|
|
227
239
|
|
|
228
|
-
- `
|
|
229
|
-
- `
|
|
240
|
+
- `mcp__plugin_aide_aide__code_outline` - **Start here.** Get collapsed file skeleton to identify functions before reading
|
|
241
|
+
- `mcp__plugin_aide_aide__code_search` - Find function/class/type definitions by name
|
|
242
|
+
- `mcp__plugin_aide_aide__code_symbols` - List all symbol definitions in a file
|
|
243
|
+
- `mcp__plugin_aide_aide__code_references` - Find all callers of a hot function (exact name match)
|
|
230
244
|
- `mcp__plugin_aide_aide__memory_search` - Check past performance decisions
|
|
245
|
+
- **Grep** - Find code patterns in bodies: loops, queries, call chains, string literals
|
|
231
246
|
|
|
232
247
|
## Profiling Commands Reference
|
|
233
248
|
|
|
234
249
|
### Node.js
|
|
250
|
+
|
|
235
251
|
```bash
|
|
236
252
|
# CPU profiling
|
|
237
253
|
node --cpu-prof app.js
|
|
@@ -247,6 +263,7 @@ npx clinic flame -- node app.js
|
|
|
247
263
|
```
|
|
248
264
|
|
|
249
265
|
### Go
|
|
266
|
+
|
|
250
267
|
```bash
|
|
251
268
|
# CPU profiling
|
|
252
269
|
go test -cpuprofile=cpu.prof -bench=.
|
|
@@ -262,6 +279,7 @@ go tool trace trace.out
|
|
|
262
279
|
```
|
|
263
280
|
|
|
264
281
|
### Browser
|
|
282
|
+
|
|
265
283
|
- DevTools -> Performance -> Record
|
|
266
284
|
- DevTools -> Memory -> Heap snapshot
|
|
267
285
|
- Lighthouse for overall page performance
|
|
@@ -269,6 +287,7 @@ go tool trace trace.out
|
|
|
269
287
|
## Verification Criteria
|
|
270
288
|
|
|
271
289
|
Before completing:
|
|
290
|
+
|
|
272
291
|
- [ ] Baseline measurement recorded
|
|
273
292
|
- [ ] Improvement quantified (percentage)
|
|
274
293
|
- [ ] All tests still pass
|
|
@@ -281,25 +300,30 @@ Before completing:
|
|
|
281
300
|
## Performance Analysis: [Operation/Endpoint Name]
|
|
282
301
|
|
|
283
302
|
### Baseline
|
|
303
|
+
|
|
284
304
|
- Execution time: 450ms (p50), 680ms (p95)
|
|
285
305
|
- Memory: 125MB peak
|
|
286
306
|
- Database queries: 150
|
|
287
307
|
|
|
288
308
|
### Hotspots Identified
|
|
309
|
+
|
|
289
310
|
1. `db.getUsers()` - 300ms (67% of total)
|
|
290
311
|
2. `processData()` - 100ms (22% of total)
|
|
291
312
|
3. `formatOutput()` - 50ms (11% of total)
|
|
292
313
|
|
|
293
314
|
### Optimizations Applied
|
|
315
|
+
|
|
294
316
|
1. Batched user queries - 300ms -> 50ms
|
|
295
317
|
2. Memoized processData for repeated calls - 100ms -> 5ms
|
|
296
318
|
|
|
297
319
|
### Results
|
|
320
|
+
|
|
298
321
|
- Execution time: 450ms -> 105ms (77% faster)
|
|
299
322
|
- Memory: 125MB -> 80MB (36% reduction)
|
|
300
323
|
- Database queries: 150 -> 3 (98% reduction)
|
|
301
324
|
|
|
302
325
|
### Verification
|
|
326
|
+
|
|
303
327
|
- All tests: PASS
|
|
304
328
|
- Output correctness: VERIFIED
|
|
305
329
|
```
|
package/skills/review/SKILL.md
CHANGED
|
@@ -18,6 +18,7 @@ Comprehensive code review covering quality, security, and maintainability.
|
|
|
18
18
|
## Review Checklist
|
|
19
19
|
|
|
20
20
|
### Code Quality
|
|
21
|
+
|
|
21
22
|
- [ ] Clear naming (variables, functions, classes)
|
|
22
23
|
- [ ] Single responsibility (functions do one thing)
|
|
23
24
|
- [ ] DRY (no unnecessary duplication)
|
|
@@ -26,6 +27,7 @@ Comprehensive code review covering quality, security, and maintainability.
|
|
|
26
27
|
- [ ] Edge cases considered
|
|
27
28
|
|
|
28
29
|
### Security (OWASP Top 10)
|
|
30
|
+
|
|
29
31
|
- [ ] Input validation (no injection vulnerabilities)
|
|
30
32
|
- [ ] Authentication checks (routes protected)
|
|
31
33
|
- [ ] Authorization (proper access control)
|
|
@@ -36,6 +38,7 @@ Comprehensive code review covering quality, security, and maintainability.
|
|
|
36
38
|
- [ ] Secure dependencies (no known vulnerabilities)
|
|
37
39
|
|
|
38
40
|
### Maintainability
|
|
41
|
+
|
|
39
42
|
- [ ] Code is readable without comments
|
|
40
43
|
- [ ] Comments explain "why" not "what"
|
|
41
44
|
- [ ] Consistent with codebase patterns
|
|
@@ -43,28 +46,47 @@ Comprehensive code review covering quality, security, and maintainability.
|
|
|
43
46
|
- [ ] No dead code
|
|
44
47
|
|
|
45
48
|
### Performance
|
|
49
|
+
|
|
46
50
|
- [ ] No N+1 queries
|
|
47
51
|
- [ ] Appropriate caching
|
|
48
52
|
- [ ] No memory leaks
|
|
49
53
|
- [ ] Efficient algorithms
|
|
50
54
|
|
|
55
|
+
## Context-Efficient Reading
|
|
56
|
+
|
|
57
|
+
Prefer lightweight tools first, then read in detail where needed:
|
|
58
|
+
|
|
59
|
+
- **`code_outline`** -- Collapsed skeleton with signatures and line ranges. Great first step for unfamiliar files.
|
|
60
|
+
- **`code_symbols`** -- Quick symbol list when you only need names and kinds.
|
|
61
|
+
- **`code_search`** / **`code_references`** -- Find symbol definitions or callers across the codebase.
|
|
62
|
+
- **`Read` with offset/limit** -- Read specific functions using line numbers from the outline.
|
|
63
|
+
- **Grep** -- Find patterns in code content (loops, queries, string literals) that the index doesn't cover.
|
|
64
|
+
|
|
65
|
+
For reviews spanning many files, consider using **Task sub-agents** (`explore` type) which run in their
|
|
66
|
+
own context and return summaries.
|
|
67
|
+
|
|
51
68
|
## Review Process
|
|
52
69
|
|
|
53
|
-
1. **
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
70
|
+
1. **Outline changed files** - Use `code_outline` on each changed file to understand structure.
|
|
71
|
+
Identify areas of concern from signatures and line ranges.
|
|
72
|
+
2. **Read targeted sections** - Use `Read` with `offset`/`limit` to read only the specific
|
|
73
|
+
functions/sections that need detailed review (use line numbers from the outline).
|
|
74
|
+
3. **Search for context** - Use `code_search`, `code_references`, and **Grep**:
|
|
75
|
+
- `code_search` — Find related function/class/type _definitions_ by name
|
|
76
|
+
- `code_references` — Find all callers/usages of a modified symbol (exact name match)
|
|
77
|
+
- **Grep** — Find code _patterns_ in bodies (error handling, SQL queries, security-sensitive calls)
|
|
78
|
+
4. **Check integration** - How does it fit the larger system?
|
|
79
|
+
5. **Run static analysis** - Use lsp_diagnostics, ast_grep if available
|
|
80
|
+
6. **Document findings** - Use severity levels
|
|
61
81
|
|
|
62
82
|
## MCP Tools
|
|
63
83
|
|
|
64
84
|
Use these tools during review:
|
|
65
85
|
|
|
86
|
+
- `mcp__plugin_aide_aide__code_outline` - **Start here.** Get collapsed file skeleton with signatures and line ranges
|
|
66
87
|
- `mcp__plugin_aide_aide__code_search` - Find symbols related to changes (e.g., `code_search query="getUserById"`)
|
|
67
88
|
- `mcp__plugin_aide_aide__code_symbols` - List all symbols in a file being reviewed
|
|
89
|
+
- `mcp__plugin_aide_aide__code_references` - Find all callers/usages of a modified symbol
|
|
68
90
|
- `mcp__plugin_aide_aide__memory_search` - Check for related past decisions or issues
|
|
69
91
|
|
|
70
92
|
## Output Format
|
|
@@ -73,28 +95,34 @@ Use these tools during review:
|
|
|
73
95
|
## Code Review: [Feature/PR Name]
|
|
74
96
|
|
|
75
97
|
### Summary
|
|
98
|
+
|
|
76
99
|
[1-2 sentence overview]
|
|
77
100
|
|
|
78
101
|
### Findings
|
|
79
102
|
|
|
80
103
|
#### 🔴 Critical (must fix)
|
|
104
|
+
|
|
81
105
|
- **[Issue]** `file:line`
|
|
82
106
|
- Problem: [description]
|
|
83
107
|
- Fix: [recommendation]
|
|
84
108
|
|
|
85
109
|
#### 🟡 Warning (should fix)
|
|
110
|
+
|
|
86
111
|
- **[Issue]** `file:line`
|
|
87
112
|
- Problem: [description]
|
|
88
113
|
- Fix: [recommendation]
|
|
89
114
|
|
|
90
115
|
#### 🔵 Suggestion (consider)
|
|
116
|
+
|
|
91
117
|
- **[Issue]** `file:line`
|
|
92
118
|
- Suggestion: [recommendation]
|
|
93
119
|
|
|
94
120
|
### Security Notes
|
|
121
|
+
|
|
95
122
|
- [Any security-specific observations]
|
|
96
123
|
|
|
97
124
|
### Verdict
|
|
125
|
+
|
|
98
126
|
[ ] ✅ Approve
|
|
99
127
|
[ ] ⚠️ Approve with comments
|
|
100
128
|
[ ] ❌ Request changes
|
|
@@ -102,11 +130,11 @@ Use these tools during review:
|
|
|
102
130
|
|
|
103
131
|
## Severity Guide
|
|
104
132
|
|
|
105
|
-
| Level
|
|
106
|
-
|
|
107
|
-
| Critical
|
|
108
|
-
| Warning
|
|
109
|
-
| Suggestion | Style, minor improvement, optional
|
|
133
|
+
| Level | Criteria |
|
|
134
|
+
| ---------- | ------------------------------------------------- |
|
|
135
|
+
| Critical | Security vulnerability, data loss risk, crash |
|
|
136
|
+
| Warning | Bug potential, maintainability issue, performance |
|
|
137
|
+
| Suggestion | Style, minor improvement, optional |
|
|
110
138
|
|
|
111
139
|
## Failure Handling
|
|
112
140
|
|
|
@@ -122,10 +150,12 @@ Use these tools during review:
|
|
|
122
150
|
## Review Status: Incomplete
|
|
123
151
|
|
|
124
152
|
### Blockers
|
|
153
|
+
|
|
125
154
|
- Could not access: `path/to/file.ts` (permission denied)
|
|
126
155
|
- Missing context: Need to understand `AuthService` implementation
|
|
127
156
|
|
|
128
157
|
### Partial Findings
|
|
158
|
+
|
|
129
159
|
[Include any findings from files that were reviewed]
|
|
130
160
|
```
|
|
131
161
|
|
|
@@ -133,14 +163,16 @@ Use these tools during review:
|
|
|
133
163
|
|
|
134
164
|
A complete code review must:
|
|
135
165
|
|
|
136
|
-
1. **
|
|
137
|
-
2. **
|
|
138
|
-
3. **
|
|
139
|
-
4. **
|
|
166
|
+
1. **Outline all changed files** - Use `code_outline` on every file in scope
|
|
167
|
+
2. **Read critical sections** - Use targeted `Read` with offset/limit on flagged areas
|
|
168
|
+
3. **Check for related code** - Use `code_search` and `code_references` to find callers/callees
|
|
169
|
+
4. **Verify test coverage** - Check if tests exist for critical paths
|
|
170
|
+
5. **Document all findings** - Even if no issues found, state that explicitly
|
|
140
171
|
|
|
141
172
|
### Checklist before submitting review:
|
|
142
173
|
|
|
143
|
-
- [ ] All files in diff/scope have been
|
|
174
|
+
- [ ] All files in diff/scope have been outlined
|
|
175
|
+
- [ ] Critical functions/sections read in detail (with offset/limit)
|
|
144
176
|
- [ ] Related symbols searched (callers, implementations)
|
|
145
177
|
- [ ] Security checklist evaluated
|
|
146
178
|
- [ ] Findings documented with file:line references
|
package/skills/test/SKILL.md
CHANGED
|
@@ -17,6 +17,7 @@ Write comprehensive tests and run test suites.
|
|
|
17
17
|
## Prerequisites
|
|
18
18
|
|
|
19
19
|
Before starting:
|
|
20
|
+
|
|
20
21
|
- Identify the code to be tested (function, module, feature)
|
|
21
22
|
- Understand the testing framework used in the project
|
|
22
23
|
|
|
@@ -27,6 +28,7 @@ Before starting:
|
|
|
27
28
|
Use the `mcp__plugin_aide_aide__decision_get` tool with topic `testing` to check for testing framework decisions.
|
|
28
29
|
|
|
29
30
|
Common frameworks by language:
|
|
31
|
+
|
|
30
32
|
- **TypeScript/JavaScript:** Vitest, Jest, Mocha
|
|
31
33
|
- **Go:** built-in `go test`
|
|
32
34
|
- **Python:** pytest, unittest
|
|
@@ -34,13 +36,18 @@ Common frameworks by language:
|
|
|
34
36
|
### Step 2: Discover Existing Test Patterns
|
|
35
37
|
|
|
36
38
|
Use `Glob` to find test files:
|
|
39
|
+
|
|
37
40
|
- Pattern: `**/*.test.ts`, `**/*.spec.ts` (TypeScript)
|
|
38
41
|
- Pattern: `**/*_test.go` (Go)
|
|
39
42
|
- Pattern: `**/test_*.py`, `**/*_test.py` (Python)
|
|
40
43
|
|
|
41
|
-
Use
|
|
44
|
+
Use **Grep** to find test patterns in existing test files:
|
|
45
|
+
|
|
46
|
+
- `Grep pattern="describe\(" include="*.test.*"` — find test suites
|
|
47
|
+
- `Grep pattern="it\(|test\(" include="*.test.*"` — find test cases
|
|
42
48
|
|
|
43
49
|
Read an existing test file to understand:
|
|
50
|
+
|
|
44
51
|
- Import patterns
|
|
45
52
|
- Setup/teardown patterns
|
|
46
53
|
- Mocking approach
|
|
@@ -52,6 +59,7 @@ Use `mcp__plugin_aide_aide__code_symbols` with the target file path to get funct
|
|
|
52
59
|
Use `mcp__plugin_aide_aide__code_search` to find related types.
|
|
53
60
|
|
|
54
61
|
Identify:
|
|
62
|
+
|
|
55
63
|
- Input parameters and types
|
|
56
64
|
- Return type
|
|
57
65
|
- Side effects
|
|
@@ -63,12 +71,14 @@ Identify:
|
|
|
63
71
|
Follow the project's testing conventions. Cover these scenarios:
|
|
64
72
|
|
|
65
73
|
**Test Categories:**
|
|
74
|
+
|
|
66
75
|
1. **Happy path** - Normal, expected inputs
|
|
67
76
|
2. **Edge cases** - Empty, null, boundary values
|
|
68
77
|
3. **Error cases** - Invalid inputs, expected failures
|
|
69
78
|
4. **Async behavior** - If applicable
|
|
70
79
|
|
|
71
80
|
**Naming convention:**
|
|
81
|
+
|
|
72
82
|
- Descriptive names that explain what is being tested
|
|
73
83
|
- Format: "should [expected behavior] when [condition]"
|
|
74
84
|
|
|
@@ -103,51 +113,52 @@ go tool cover -html=coverage.out
|
|
|
103
113
|
```
|
|
104
114
|
|
|
105
115
|
**Coverage targets:**
|
|
116
|
+
|
|
106
117
|
- New code: aim for >80%
|
|
107
118
|
- Critical paths: aim for >90%
|
|
108
119
|
- Focus on meaningful tests, not just coverage numbers
|
|
109
120
|
|
|
110
121
|
## Failure Handling
|
|
111
122
|
|
|
112
|
-
| Failure
|
|
113
|
-
|
|
114
|
-
| Test imports fail
|
|
115
|
-
| Mock not working
|
|
116
|
-
| Async test timeout | Add proper await, increase timeout if needed
|
|
117
|
-
| Flaky test
|
|
118
|
-
| Coverage too low
|
|
123
|
+
| Failure | Action |
|
|
124
|
+
| ------------------ | ------------------------------------------------------- |
|
|
125
|
+
| Test imports fail | Check path aliases, ensure test config matches main |
|
|
126
|
+
| Mock not working | Verify mock setup, check dependency injection |
|
|
127
|
+
| Async test timeout | Add proper await, increase timeout if needed |
|
|
128
|
+
| Flaky test | Check for shared state, timing issues, or external deps |
|
|
129
|
+
| Coverage too low | Add edge case tests, error path tests |
|
|
119
130
|
|
|
120
131
|
## Test Structure Templates
|
|
121
132
|
|
|
122
133
|
### TypeScript/JavaScript (Vitest/Jest)
|
|
123
134
|
|
|
124
135
|
```typescript
|
|
125
|
-
import { describe, it, expect, beforeEach, vi } from
|
|
126
|
-
import { functionToTest } from
|
|
136
|
+
import { describe, it, expect, beforeEach, vi } from "vitest";
|
|
137
|
+
import { functionToTest } from "./module";
|
|
127
138
|
|
|
128
|
-
describe(
|
|
139
|
+
describe("functionToTest", () => {
|
|
129
140
|
beforeEach(() => {
|
|
130
141
|
// Reset state before each test
|
|
131
142
|
vi.clearAllMocks();
|
|
132
143
|
});
|
|
133
144
|
|
|
134
|
-
it(
|
|
135
|
-
const result = functionToTest(
|
|
136
|
-
expect(result).toBe(
|
|
145
|
+
it("should return expected result for valid input", () => {
|
|
146
|
+
const result = functionToTest("valid input");
|
|
147
|
+
expect(result).toBe("expected output");
|
|
137
148
|
});
|
|
138
149
|
|
|
139
|
-
it(
|
|
140
|
-
const result = functionToTest(
|
|
141
|
-
expect(result).toBe(
|
|
150
|
+
it("should handle empty input", () => {
|
|
151
|
+
const result = functionToTest("");
|
|
152
|
+
expect(result).toBe("");
|
|
142
153
|
});
|
|
143
154
|
|
|
144
|
-
it(
|
|
145
|
-
expect(() => functionToTest(null)).toThrow(
|
|
155
|
+
it("should throw error for null input", () => {
|
|
156
|
+
expect(() => functionToTest(null)).toThrow("Input required");
|
|
146
157
|
});
|
|
147
158
|
|
|
148
|
-
it(
|
|
149
|
-
const result = await functionToTest(
|
|
150
|
-
expect(result).resolves.toBe(
|
|
159
|
+
it("should handle async operation", async () => {
|
|
160
|
+
const result = await functionToTest("async input");
|
|
161
|
+
expect(result).resolves.toBe("async output");
|
|
151
162
|
});
|
|
152
163
|
});
|
|
153
164
|
```
|
|
@@ -213,6 +224,7 @@ class TestFunctionToTest:
|
|
|
213
224
|
## Verification Criteria
|
|
214
225
|
|
|
215
226
|
Before completing:
|
|
227
|
+
|
|
216
228
|
- [ ] All new tests pass
|
|
217
229
|
- [ ] Existing tests still pass
|
|
218
230
|
- [ ] Coverage meets project standards
|
|
@@ -225,9 +237,11 @@ Before completing:
|
|
|
225
237
|
## Tests Added
|
|
226
238
|
|
|
227
239
|
### Files
|
|
240
|
+
|
|
228
241
|
- `path/to/file.test.ts` - 5 tests for UserService
|
|
229
242
|
|
|
230
243
|
### Test Cases
|
|
244
|
+
|
|
231
245
|
1. should create user with valid data
|
|
232
246
|
2. should reject duplicate email
|
|
233
247
|
3. should hash password before saving
|
|
@@ -235,10 +249,12 @@ Before completing:
|
|
|
235
249
|
5. should validate email format
|
|
236
250
|
|
|
237
251
|
### Coverage
|
|
252
|
+
|
|
238
253
|
- New code: 92%
|
|
239
254
|
- Total project: 84%
|
|
240
255
|
|
|
241
256
|
### Verification
|
|
257
|
+
|
|
242
258
|
- All tests: PASS
|
|
243
259
|
- No flaky tests observed
|
|
244
260
|
```
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Guard — platform-agnostic core logic.
|
|
3
|
+
*
|
|
4
|
+
* Monitors Read tool calls and advises agents to use code_outline
|
|
5
|
+
* before reading large files. This preserves context window for
|
|
6
|
+
* the actual task by avoiding dumping entire files into conversation.
|
|
7
|
+
*
|
|
8
|
+
* Behaviour:
|
|
9
|
+
* - Triggers on Read tool calls for files > 5KB (~150 lines)
|
|
10
|
+
* - Tracks which files have been outlined (code_outline/code_symbols)
|
|
11
|
+
* - Returns an advisory message (never blocks)
|
|
12
|
+
* - Also tracks code_outline/code_symbols calls to mark files as "known"
|
|
13
|
+
*
|
|
14
|
+
* Used by both Claude Code hooks (PreToolUse) and OpenCode plugin.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { statSync, readFileSync, writeFileSync, existsSync } from "fs";
|
|
18
|
+
import { resolve, isAbsolute, normalize } from "path";
|
|
19
|
+
import { tmpdir } from "os";
|
|
20
|
+
import { join } from "path";
|
|
21
|
+
import { debug } from "../lib/logger.js";
|
|
22
|
+
|
|
23
|
+
const SOURCE = "context-guard";
|
|
24
|
+
|
|
25
|
+
/** Default size threshold in bytes (~150 lines) */
|
|
26
|
+
const DEFAULT_SIZE_THRESHOLD = 5120;
|
|
27
|
+
|
|
28
|
+
/** File extensions that are typically not source code (skip advisory) */
|
|
29
|
+
const SKIP_EXTENSIONS = new Set([
|
|
30
|
+
".json",
|
|
31
|
+
".lock",
|
|
32
|
+
".sum",
|
|
33
|
+
".mod",
|
|
34
|
+
".yaml",
|
|
35
|
+
".yml",
|
|
36
|
+
".toml",
|
|
37
|
+
".env",
|
|
38
|
+
".md",
|
|
39
|
+
".txt",
|
|
40
|
+
".csv",
|
|
41
|
+
".svg",
|
|
42
|
+
".png",
|
|
43
|
+
".jpg",
|
|
44
|
+
".gif",
|
|
45
|
+
".ico",
|
|
46
|
+
".woff",
|
|
47
|
+
".woff2",
|
|
48
|
+
".ttf",
|
|
49
|
+
".eot",
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
export interface ContextGuardResult {
|
|
53
|
+
/** Whether to inject an advisory message */
|
|
54
|
+
shouldAdvise: boolean;
|
|
55
|
+
/** Advisory message to inject */
|
|
56
|
+
advisory?: string;
|
|
57
|
+
/** Whether this call should be tracked (code_outline/code_symbols) */
|
|
58
|
+
tracked?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Get the path to the tracking file for this session.
|
|
63
|
+
*/
|
|
64
|
+
function getTrackingPath(sessionId: string): string {
|
|
65
|
+
return join(tmpdir(), `aide-context-guard-${sessionId}.json`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Load the set of files that have been outlined in this session.
|
|
70
|
+
*/
|
|
71
|
+
function loadOutlinedFiles(sessionId: string): Set<string> {
|
|
72
|
+
const trackingPath = getTrackingPath(sessionId);
|
|
73
|
+
try {
|
|
74
|
+
if (existsSync(trackingPath)) {
|
|
75
|
+
const data = JSON.parse(readFileSync(trackingPath, "utf-8"));
|
|
76
|
+
return new Set(data.files || []);
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// Corrupted file, start fresh
|
|
80
|
+
}
|
|
81
|
+
return new Set();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Save a file as "outlined" in the tracking file.
|
|
86
|
+
*/
|
|
87
|
+
function trackOutlinedFile(sessionId: string, filePath: string): void {
|
|
88
|
+
const files = loadOutlinedFiles(sessionId);
|
|
89
|
+
files.add(filePath);
|
|
90
|
+
const trackingPath = getTrackingPath(sessionId);
|
|
91
|
+
try {
|
|
92
|
+
writeFileSync(
|
|
93
|
+
trackingPath,
|
|
94
|
+
JSON.stringify({ files: Array.from(files) }),
|
|
95
|
+
"utf-8",
|
|
96
|
+
);
|
|
97
|
+
} catch (err) {
|
|
98
|
+
debug(SOURCE, `Failed to write tracking file: ${err}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Estimate line count from file size (rough: ~35 bytes per line average).
|
|
104
|
+
*/
|
|
105
|
+
function estimateLines(sizeBytes: number): number {
|
|
106
|
+
return Math.round(sizeBytes / 35);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Check whether a Read call should receive a context-efficiency advisory.
|
|
111
|
+
*
|
|
112
|
+
* Also handles tracking code_outline/code_symbols calls.
|
|
113
|
+
*/
|
|
114
|
+
export function checkContextGuard(
|
|
115
|
+
toolName: string,
|
|
116
|
+
toolInput: Record<string, unknown>,
|
|
117
|
+
cwd: string,
|
|
118
|
+
sessionId: string,
|
|
119
|
+
): ContextGuardResult {
|
|
120
|
+
const normalizedTool = toolName.toLowerCase();
|
|
121
|
+
|
|
122
|
+
// Track code_outline and code_symbols calls
|
|
123
|
+
if (
|
|
124
|
+
normalizedTool.includes("code_outline") ||
|
|
125
|
+
normalizedTool.includes("code_symbols")
|
|
126
|
+
) {
|
|
127
|
+
const filePath =
|
|
128
|
+
(toolInput.file as string) ||
|
|
129
|
+
(toolInput.filePath as string) ||
|
|
130
|
+
(toolInput.file_path as string);
|
|
131
|
+
if (filePath && sessionId) {
|
|
132
|
+
const resolved = normalize(
|
|
133
|
+
isAbsolute(filePath) ? filePath : resolve(cwd, filePath),
|
|
134
|
+
);
|
|
135
|
+
trackOutlinedFile(sessionId, resolved);
|
|
136
|
+
debug(SOURCE, `Tracked outline for: ${filePath}`);
|
|
137
|
+
}
|
|
138
|
+
return { shouldAdvise: false, tracked: true };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Only advise on Read tool calls
|
|
142
|
+
if (normalizedTool !== "read") {
|
|
143
|
+
return { shouldAdvise: false };
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Extract file path from tool input
|
|
147
|
+
const filePath =
|
|
148
|
+
(toolInput.filePath as string) ||
|
|
149
|
+
(toolInput.file_path as string) ||
|
|
150
|
+
(toolInput.path as string);
|
|
151
|
+
|
|
152
|
+
if (!filePath) {
|
|
153
|
+
return { shouldAdvise: false };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Resolve to absolute path
|
|
157
|
+
const resolvedPath = normalize(
|
|
158
|
+
isAbsolute(filePath) ? filePath : resolve(cwd, filePath),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Skip non-source-code files
|
|
162
|
+
const ext = filePath.substring(filePath.lastIndexOf(".")).toLowerCase();
|
|
163
|
+
if (SKIP_EXTENSIONS.has(ext)) {
|
|
164
|
+
return { shouldAdvise: false };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Check if the agent is already using offset/limit (targeted read)
|
|
168
|
+
const offset = toolInput.offset as number | undefined;
|
|
169
|
+
const limit = toolInput.limit as number | undefined;
|
|
170
|
+
if (offset !== undefined && offset > 1) {
|
|
171
|
+
// Agent is doing a targeted read — no advisory needed
|
|
172
|
+
return { shouldAdvise: false };
|
|
173
|
+
}
|
|
174
|
+
if (limit !== undefined && limit < 100) {
|
|
175
|
+
// Agent is limiting the read — no advisory needed
|
|
176
|
+
return { shouldAdvise: false };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Check file size
|
|
180
|
+
let fileSize: number;
|
|
181
|
+
try {
|
|
182
|
+
const stat = statSync(resolvedPath);
|
|
183
|
+
fileSize = stat.size;
|
|
184
|
+
} catch {
|
|
185
|
+
// Can't stat file — don't advise (file might not exist yet)
|
|
186
|
+
return { shouldAdvise: false };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Skip small files
|
|
190
|
+
if (fileSize < DEFAULT_SIZE_THRESHOLD) {
|
|
191
|
+
return { shouldAdvise: false };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Check if this file has already been outlined in this session
|
|
195
|
+
if (sessionId) {
|
|
196
|
+
const outlinedFiles = loadOutlinedFiles(sessionId);
|
|
197
|
+
if (outlinedFiles.has(resolvedPath)) {
|
|
198
|
+
debug(SOURCE, `File already outlined, skipping advisory: ${filePath}`);
|
|
199
|
+
return { shouldAdvise: false };
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Generate advisory
|
|
204
|
+
const estLines = estimateLines(fileSize);
|
|
205
|
+
const sizeKB = (fileSize / 1024).toFixed(1);
|
|
206
|
+
|
|
207
|
+
const advisory =
|
|
208
|
+
`[aide:context] This file is ~${estLines} lines (${sizeKB}KB). Consider using \`code_outline\` ` +
|
|
209
|
+
`first to see its structure, then \`Read\` with offset/limit for specific sections. ` +
|
|
210
|
+
`This preserves your context window for the full task.`;
|
|
211
|
+
|
|
212
|
+
debug(SOURCE, `Advisory for ${filePath}: ${estLines} lines, ${sizeKB}KB`);
|
|
213
|
+
return { shouldAdvise: true, advisory };
|
|
214
|
+
}
|
package/src/opencode/index.ts
CHANGED
|
@@ -156,8 +156,8 @@ export const AidePlugin: Plugin = async (ctx: PluginInput): Promise<Hooks> => {
|
|
|
156
156
|
// Plugin may be called before the client is fully ready
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
// Also log to stderr
|
|
160
|
-
console.error(rawLog);
|
|
159
|
+
// Also log to stderr when debugging
|
|
160
|
+
if (process.env.AIDE_DEBUG === "1") console.error(rawLog);
|
|
161
161
|
|
|
162
162
|
const resolved = resolveProjectRoot(ctx);
|
|
163
163
|
|
|
@@ -170,7 +170,7 @@ export const AidePlugin: Plugin = async (ctx: PluginInput): Promise<Hooks> => {
|
|
|
170
170
|
} catch {
|
|
171
171
|
// non-fatal
|
|
172
172
|
}
|
|
173
|
-
console.error(resolvedLog);
|
|
173
|
+
if (process.env.AIDE_DEBUG === "1") console.error(resolvedLog);
|
|
174
174
|
|
|
175
175
|
return createHooks(resolved.root, ctx.worktree, ctx.client, pluginRoot, {
|
|
176
176
|
skipInit: !resolved.hasProjectRoot,
|