Skip to content

Commit a739357

Browse files
authored
Merge pull request #6 from sdsrss/feat/plugin-integration-audit
feat(plugin): convert commands to skills, fix intent detection, add E2E tests
2 parents c89fd6f + 64ac15e commit a739357

32 files changed

Lines changed: 1047 additions & 214 deletions

CLAUDE.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,18 @@ Code graph tools are available via MCP. The MCP server injects `instructions` at
6161

6262
<claude-mem-context>
6363
### Last Session
64-
Request: 配置提交代码时的git pre-commit hook检查和代码审核工具,避免下次github上再出现错误。 Pre-commit hook (scripts/pre-commit.sh): ┌──────────┬────…
65-
Completed: Modified package.json, .gitignore; Modified pre-commit.sh
66-
67-
### File Lessons
68-
- cli.rs: Embedding availability must be validated before semantic search to prevent runtime errors; distingu… (#5321)
64+
Request: Simulate user-level testing of all code-graph-mcp functions and UX, fix discovered problems, evaluate programming effic…
65+
Completed: Fixed tools.rs compilation (Phase 3 result-building); Modified pipeline.rs (default resolution logic); Created SKILL.md…
66+
Remaining: Comprehensive UX testing not executed; Loop plugin 3-iteration execution not performed; Functional testing of all code-…
67+
Next: 1) Execute user-level functional testing workflow via loop plugin (3× as specified); 2) Document UX findings and issues…
68+
Lessons: Phase 3 result struct initialization in tools.rs requires explicit type handling; Multi-file code pattern searches needed to identify incomplete reference mapping implementations
69+
Decisions: Prioritized compilation correctness (tools.rs, pipeline.rs) before comprehensive UX testing; Created SKILL.md to improve project discoverability and functionality documentation
6970

7071
### Key Context
71-
- [bugfix] Error: queries.rs: Error: Usage: code-graph-mcp search <query> --jso… (#5267)
72-
- [bugfix] Error: session-init.test.js: TAP version 13 # Subtest: syncLifecycleConfig is … (#5202)
73-
- [bugfix] Error: user-prompt-context.js, session-init.js, mcp-launcher.js: TAP version 13… (#5200)
74-
- [bugfix] Error: cli.rs: struct Database src/storage/db.rs:30-33 fn McpSe… (#5096)
75-
- [bugfix] Error: cli.rs: code-graph Symbol not found: --- code-graph No r… (#5079)
72+
- [discovery] Reviewed 2 files: treesitter.rs, relations.rs (#5740)
73+
- [refactor] Remove unused thread import from watcher.rs (#5714)
74+
- [bugfix] Error: tools.rs: Compiling code-graph-mcp v0.7.14 (/mnt/data_ssd/d… (#5701)
75+
- [bugfix] Error: tools.rs: error: Your local changes to the following files … (#5697)
76+
- [change] Add idempotent column insertion checks to schema.rs (#5696)
7677

7778
</claude-mem-context>

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

claude-plugin/commands/impact.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

claude-plugin/commands/rebuild.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

claude-plugin/commands/status.md

Lines changed: 0 additions & 5 deletions
This file was deleted.

claude-plugin/commands/trace.md

Lines changed: 0 additions & 12 deletions
This file was deleted.

claude-plugin/commands/understand.md

Lines changed: 0 additions & 12 deletions
This file was deleted.

claude-plugin/scripts/pre-edit-guide.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,14 @@ if (!symbol || symbol.length < 3) {
8989
if (!symbol || symbol.length < 3) process.exit(0);
9090

9191
// Skip common patterns that aren't real function names
92-
if (/^(if|for|while|switch|catch|else|return|new|get|set|try)$/i.test(symbol)) {
92+
if (isCommonKeyword(symbol)) {
9393
process.exit(0);
9494
}
9595

96+
function isCommonKeyword(s) {
97+
return /^(if|for|while|switch|catch|else|return|new|get|set|try)$/i.test(s);
98+
}
99+
96100
// --- Per-symbol cooldown: 2 minutes ---
97101
const cooldownFile = path.join(os.tmpdir(), `.cg-impact-${symbol}`);
98102
try {
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
'use strict';
2+
const test = require('node:test');
3+
const assert = require('node:assert/strict');
4+
5+
// Pre-edit-guide.js is a script with side effects (reads stdin, checks db).
6+
// We test its PATTERNS directly without requiring the module.
7+
8+
// --- Function signature patterns (copied from pre-edit-guide.js) ---
9+
const fnPatterns = [
10+
/(?:pub\s+)?(?:async\s+)?fn\s+(\w+)/, // Rust
11+
/(?:export\s+)?(?:async\s+)?function\s+(\w+)/, // JS/TS
12+
/(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|_)\s*=>/, // JS arrow
13+
/(?:async\s+)?(\w+)\s*\([^)]*\)\s*\{/, // JS method / Go func
14+
/def\s+(\w+)/, // Python/Ruby
15+
/func\s+(\w+)/, // Go/Swift
16+
/(?:public|private|protected|static|override|virtual|abstract|internal)\s+\S+\s+(\w+)\s*\(/, // Java/C#/Kotlin
17+
/(?:public\s+)?function\s+(\w+)/, // PHP
18+
];
19+
20+
function extractFunctionName(code) {
21+
for (const pat of fnPatterns) {
22+
const m = code.match(pat);
23+
if (m) return m[1] || m[2];
24+
}
25+
return null;
26+
}
27+
28+
function isCommonKeyword(s) {
29+
return /^(if|for|while|switch|catch|else|return|new|get|set|try)$/i.test(s);
30+
}
31+
32+
// ── Rust ────────────────────────────────────────────────
33+
34+
test('fn-extract: Rust pub fn', () => {
35+
assert.equal(extractFunctionName('pub fn parse_code(input: &str) -> Vec<Node> {'), 'parse_code');
36+
});
37+
38+
test('fn-extract: Rust pub async fn', () => {
39+
assert.equal(extractFunctionName('pub async fn handle_message(&self, msg: &str) -> Result<()> {'), 'handle_message');
40+
});
41+
42+
test('fn-extract: Rust fn (no pub)', () => {
43+
assert.equal(extractFunctionName('fn helper_func(x: i32) -> i32 {'), 'helper_func');
44+
});
45+
46+
// ── JavaScript/TypeScript ───────────────────────────────
47+
48+
test('fn-extract: JS function', () => {
49+
assert.equal(extractFunctionName('function handleRequest(req, res) {'), 'handleRequest');
50+
});
51+
52+
test('fn-extract: JS export function', () => {
53+
assert.equal(extractFunctionName('export function processData(input) {'), 'processData');
54+
});
55+
56+
test('fn-extract: JS async function', () => {
57+
assert.equal(extractFunctionName('async function fetchData(url) {'), 'fetchData');
58+
});
59+
60+
test('fn-extract: JS export async function', () => {
61+
assert.equal(extractFunctionName('export async function loadConfig(path) {'), 'loadConfig');
62+
});
63+
64+
test('fn-extract: JS arrow function (const)', () => {
65+
assert.equal(extractFunctionName('const handleError = (err) => {'), 'handleError');
66+
});
67+
68+
test('fn-extract: JS arrow function (async)', () => {
69+
assert.equal(extractFunctionName('const fetchUser = async (id) => {'), 'fetchUser');
70+
});
71+
72+
test('fn-extract: JS method', () => {
73+
assert.equal(extractFunctionName(' handleMessage(msg) {'), 'handleMessage');
74+
});
75+
76+
// ── Python ──────────────────────────────────────────────
77+
78+
test('fn-extract: Python def', () => {
79+
assert.equal(extractFunctionName('def process_data(self, items):'), 'process_data');
80+
});
81+
82+
test('fn-extract: Python async def', () => {
83+
assert.equal(extractFunctionName('async def fetch_data(url):'), 'fetch_data');
84+
});
85+
86+
// ── Go ──────────────────────────────────────────────────
87+
88+
test('fn-extract: Go func', () => {
89+
assert.equal(extractFunctionName('func HandleRequest(w http.ResponseWriter, r *http.Request) {'), 'HandleRequest');
90+
});
91+
92+
// ── Java/C#/Kotlin ──────────────────────────────────────
93+
94+
test('fn-extract: Java public method', () => {
95+
assert.equal(extractFunctionName('public void processItem(Item item) {'), 'processItem');
96+
});
97+
98+
test('fn-extract: Java private method', () => {
99+
assert.equal(extractFunctionName('private String formatOutput(Data data) {'), 'formatOutput');
100+
});
101+
102+
test('fn-extract: C# static method', () => {
103+
assert.equal(extractFunctionName('static int CalculateTotal(List<int> items) {'), 'CalculateTotal');
104+
});
105+
106+
// ── PHP ─────────────────────────────────────────────────
107+
108+
test('fn-extract: PHP function', () => {
109+
assert.equal(extractFunctionName('function handleUpload($file) {'), 'handleUpload');
110+
});
111+
112+
test('fn-extract: PHP public function', () => {
113+
assert.equal(extractFunctionName('public function getUser($id) {'), 'getUser');
114+
});
115+
116+
// ── Ruby ────────────────────────────────────────────────
117+
118+
test('fn-extract: Ruby def', () => {
119+
assert.equal(extractFunctionName('def process_request(params)'), 'process_request');
120+
});
121+
122+
// ── Keyword filter ──────────────────────────────────────
123+
124+
test('keyword-filter: common keywords rejected', () => {
125+
for (const kw of ['if', 'for', 'while', 'switch', 'catch', 'else', 'return', 'new', 'get', 'set', 'try']) {
126+
assert.ok(isCommonKeyword(kw), `"${kw}" should be rejected`);
127+
}
128+
});
129+
130+
test('keyword-filter: real function names pass', () => {
131+
for (const name of ['parse_code', 'handleMessage', 'process_data', 'fetchUser']) {
132+
assert.ok(!isCommonKeyword(name), `"${name}" should pass`);
133+
}
134+
});
135+
136+
// ── No false positives ──────────────────────────────────
137+
138+
test('fn-extract: plain code body returns null', () => {
139+
assert.equal(extractFunctionName('let x = 42;\nreturn x + 1;'), null);
140+
});
141+
142+
test('fn-extract: comment returns null', () => {
143+
assert.equal(extractFunctionName('// This is a comment about the function'), null);
144+
});
145+
146+
test('fn-extract: short strings return null', () => {
147+
assert.equal(extractFunctionName('x = 1'), null);
148+
});
149+
150+
// ── Pattern consistency check ───────────────────────────
151+
// Verify fnPatterns in this test match what's in pre-edit-guide.js
152+
153+
test('pattern-sync: fnPatterns count matches source', () => {
154+
const fs = require('node:fs');
155+
const path = require('node:path');
156+
const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
157+
// Count regex pattern lines in the fnPatterns array (lines containing // Language comment)
158+
const sourcePatternCount = (source.match(/\/\/\s*(Rust|JS|Python|Go|Java|C#|PHP|Ruby|Swift|Kotlin)/g) || []).length;
159+
assert.ok(fnPatterns.length === 8, `Expected 8 patterns, got ${fnPatterns.length}`);
160+
assert.ok(sourcePatternCount >= 7, `Source should have >= 7 language comments, found ${sourcePatternCount}`);
161+
});

0 commit comments

Comments
 (0)