@sdsrs/code-graph 0.94.0 → 0.95.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +1 -1
  2. package/claude-plugin/scripts/auto-update.js +69 -9
  3. package/package.json +8 -7
  4. package/claude-plugin/scripts/adopt.test.js +0 -679
  5. package/claude-plugin/scripts/auto-update.test.js +0 -515
  6. package/claude-plugin/scripts/cg-answer.test.js +0 -309
  7. package/claude-plugin/scripts/claude-config.test.js +0 -58
  8. package/claude-plugin/scripts/covering-tests.test.js +0 -78
  9. package/claude-plugin/scripts/doctor.test.js +0 -215
  10. package/claude-plugin/scripts/find-binary.test.js +0 -246
  11. package/claude-plugin/scripts/hook-fire.test.js +0 -117
  12. package/claude-plugin/scripts/hooks.test.js +0 -230
  13. package/claude-plugin/scripts/incremental-index.test.js +0 -102
  14. package/claude-plugin/scripts/lifecycle.e2e.test.js +0 -179
  15. package/claude-plugin/scripts/lifecycle.test.js +0 -786
  16. package/claude-plugin/scripts/mcp-launcher.test.js +0 -162
  17. package/claude-plugin/scripts/mcp-stub.test.js +0 -207
  18. package/claude-plugin/scripts/post-grep-inject.test.js +0 -531
  19. package/claude-plugin/scripts/pr-impact-comment.test.js +0 -110
  20. package/claude-plugin/scripts/pre-edit-guide.test.js +0 -218
  21. package/claude-plugin/scripts/pre-grep-guide.test.js +0 -1682
  22. package/claude-plugin/scripts/pre-read-guide.test.js +0 -363
  23. package/claude-plugin/scripts/project-detect.test.js +0 -95
  24. package/claude-plugin/scripts/recommendation-log.test.js +0 -79
  25. package/claude-plugin/scripts/session-init.test.js +0 -479
  26. package/claude-plugin/scripts/statusline-composite.test.js +0 -65
  27. package/claude-plugin/scripts/statusline.test.js +0 -235
  28. package/claude-plugin/scripts/tmp-dir.test.js +0 -50
  29. package/claude-plugin/scripts/user-prompt-context.test.js +0 -743
  30. package/claude-plugin/scripts/version-utils.test.js +0 -141
@@ -1,218 +0,0 @@
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
- // ── Salience forcing (v0.63) ────────────────────────────
154
- // pre-edit-guide.js top-level-exits on require (reads stdin / checks db), so we
155
- // assert on the source text — same convention as pattern-sync below.
156
-
157
- test('salience: impact summary forces a per-caller verdict before the edit', () => {
158
- const fs = require('node:fs');
159
- const path = require('node:path');
160
- const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
161
- // mem lifts cite-recall to ~94% by making the model ACT on the injection; the
162
- // impact summary must do the same rather than be passively skimmed. Wording
163
- // references "each caller of X()" not "above" (finding #5) so it stays coherent
164
- // when only the caller COUNT is shown (callers[] empty but directCallers>=1).
165
- assert.match(source, /Before this edit: confirm each caller of/);
166
- assert.match(source, /still holds with your change, or note why it is unaffected/);
167
- assert.doesNotMatch(source, /caller\(s\) above you will update/); // old wording removed
168
- });
169
-
170
- test('pattern-sync: fnPatterns count matches source', () => {
171
- const fs = require('node:fs');
172
- const path = require('node:path');
173
- const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
174
- // Count regex pattern lines in the fnPatterns array (lines containing // Language comment)
175
- const sourcePatternCount = (source.match(/\/\/\s*(Rust|JS|Python|Go|Java|C#|PHP|Ruby|Swift|Kotlin)/g) || []).length;
176
- assert.ok(fnPatterns.length === 8, `Expected 8 patterns, got ${fnPatterns.length}`);
177
- assert.ok(sourcePatternCount >= 7, `Source should have >= 7 language comments, found ${sourcePatternCount}`);
178
- });
179
-
180
- // ── Covering-test targeting (edit-time PUSH) ────────────
181
- // The pure formatter lives in covering-tests.js (unit-tested in covering-tests.test.js);
182
- // these guard that the hook actually wires it in and records the forward signal.
183
- // Source-grep, same convention as the salience/pattern-sync guards (hook exits on require).
184
-
185
- test('covering-tests: hook requires and invokes the covering-tests formatter on test_callers', () => {
186
- const fs = require('node:fs');
187
- const path = require('node:path');
188
- const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
189
- assert.match(source, /require\(['"]\.\/covering-tests['"]\)/);
190
- assert.match(source, /formatCoveringTests\(/);
191
- assert.match(source, /test_callers/);
192
- });
193
-
194
- test('covering-tests: edit injection records test_targets for the forward funnel', () => {
195
- const fs = require('node:fs');
196
- const path = require('node:path');
197
- const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
198
- assert.match(source, /test_targets:/);
199
- });
200
-
201
- // ── Compound-grep sibling sweep: impact summary → additionalContext ──
202
- // Bare `process.stdout.write(summary)` on a PreToolUse exit-0 lands in the debug
203
- // log only and never reaches the model (CC docs v2026-06). The impact summary
204
- // must ride the shared PreToolUse allow+additionalContext envelope instead.
205
- // Source-grep, same convention as the salience/pattern-sync guards (hook exits
206
- // on require: reads stdin, resolves the index).
207
-
208
- test('emit: impact summary is delivered via the PreToolUse allow+additionalContext envelope', () => {
209
- const fs = require('node:fs');
210
- const path = require('node:path');
211
- const source = fs.readFileSync(path.join(__dirname, 'pre-edit-guide.js'), 'utf8');
212
- assert.match(source, /require\(['"]\.\/hook-emit['"]\)/,
213
- 'pre-edit-guide must use the shared hook-emit module (no inline envelope copy)');
214
- assert.match(source, /emitPreToolAllowContext\(summary\)/,
215
- 'the impact summary must be carried inside additionalContext, not bare stdout');
216
- assert.doesNotMatch(source, /process\.stdout\.write\(summary\)\s*;/,
217
- 'the bare stdout summary emission (debug-log-only) must be removed');
218
- });