@sdsrs/code-graph 0.155.0 → 0.156.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.
|
@@ -129,6 +129,11 @@ function firstShellClause(cmd) {
|
|
|
129
129
|
if (c === quote) quote = null;
|
|
130
130
|
continue;
|
|
131
131
|
}
|
|
132
|
+
// Outside quotes a backslash escapes the next character: `\"` opens no
|
|
133
|
+
// quote and `\;` / `\|` are literal. quotedSpans reads patterns by the same
|
|
134
|
+
// rule; a splitter that disagreed let `grep \"X\" src/ && echo "Y"` hand the
|
|
135
|
+
// echo's `Y` to the pattern reader (pre-ship review F1).
|
|
136
|
+
if (c === '\\') { i++; continue; }
|
|
132
137
|
if (c === '"' || c === "'") { quote = c; continue; }
|
|
133
138
|
// Control operators END the grep's argument list → truncate. NOT redirects
|
|
134
139
|
// (`>` `<`): `2>&1`, `>out`, and process substitution `-f <(cat pats) src/`
|
|
@@ -227,8 +232,47 @@ function extractPatterns(cmd) {
|
|
|
227
232
|
// Collect every quoted argument — first one is the pattern in standard grep
|
|
228
233
|
// usage; subsequent ones (e.g. `-e "second"`) are also patterns or filter
|
|
229
234
|
// expressions and worth screening too.
|
|
230
|
-
|
|
231
|
-
|
|
235
|
+
return quotedSpans(stripped).map(s => s.body).filter(Boolean);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* The quoted spans of a shell clause, read the way the shell reads them — the
|
|
240
|
+
* rules firstShellClause, splitTopLevelSegments and extractUnansweredTail also
|
|
241
|
+
* follow (lesson #9656 inside quotes; pre-ship review F1 outside), which a span regex (`"([^"]+)"|'([^']+)'`) did not: it closed a
|
|
242
|
+
* double-quoted argument at the first `\"`, so
|
|
243
|
+
* `grep "if:\s*'\|\"if\"\|statusMessage"` yielded `\|statusMessage`, and its
|
|
244
|
+
* translation `|statusMessage` matches every line (observed 2026-09-25).
|
|
245
|
+
* - `'…'` is literal to the next `'`.
|
|
246
|
+
* - `"…"`: a backslash escapes `"` `\` `$` and backtick (the backslash is
|
|
247
|
+
* dropped) and, before a newline, removes both characters (a line
|
|
248
|
+
* continuation); before anything else it is literal (`"a\|b"`).
|
|
249
|
+
* - Outside quotes a backslash escapes the next character, so `\"` opens
|
|
250
|
+
* nothing — the shell hands grep the quote character itself.
|
|
251
|
+
* An unterminated quote ends the scan: what follows is not a span we can read.
|
|
252
|
+
* @returns {{start: number, end: number, body: string}[]} `end` is exclusive,
|
|
253
|
+
* covering both quote characters.
|
|
254
|
+
*/
|
|
255
|
+
function quotedSpans(s) {
|
|
256
|
+
const spans = [];
|
|
257
|
+
if (typeof s !== 'string') return spans;
|
|
258
|
+
for (let i = 0; i < s.length; i++) {
|
|
259
|
+
const c = s[i];
|
|
260
|
+
if (c === '\\') { i++; continue; }
|
|
261
|
+
if (c !== '"' && c !== "'") continue;
|
|
262
|
+
let body = '';
|
|
263
|
+
let j = i + 1;
|
|
264
|
+
for (; j < s.length && s[j] !== c; j++) {
|
|
265
|
+
if (c === '"' && s[j] === '\\' && j + 1 < s.length && '"\\$`\n'.includes(s[j + 1])) {
|
|
266
|
+
j++;
|
|
267
|
+
if (s[j] === '\n') continue; // backslash-newline is a line continuation: both go
|
|
268
|
+
}
|
|
269
|
+
body += s[j];
|
|
270
|
+
}
|
|
271
|
+
if (j >= s.length) break;
|
|
272
|
+
spans.push({ start: i, end: j + 1, body });
|
|
273
|
+
i = j;
|
|
274
|
+
}
|
|
275
|
+
return spans;
|
|
232
276
|
}
|
|
233
277
|
|
|
234
278
|
// Declaration anchors inside a pattern (`def cascade_failure|class TaskState`)
|
|
@@ -349,7 +393,16 @@ function isAgFilenameSearch(clause) {
|
|
|
349
393
|
// argument can contain whitespace, so `ag "some_symbol -g x" src/` splits into
|
|
350
394
|
// three tokens and the middle one looks exactly like a flag. Blanking leaves
|
|
351
395
|
// an attached value's flag behind (`-g"x"` → `-g`), which is what we want.
|
|
352
|
-
|
|
396
|
+
// Spans come from quotedSpans, not a span regex: `"a\" -g x"` is ONE
|
|
397
|
+
// argument, and a regex that closed it at the `\"` left `-g` bare.
|
|
398
|
+
const unverbed = clause.replace(VERB_STRIP, '');
|
|
399
|
+
let scan = '';
|
|
400
|
+
let at = 0;
|
|
401
|
+
for (const sp of quotedSpans(unverbed)) {
|
|
402
|
+
scan += unverbed.slice(at, sp.start) + ' ';
|
|
403
|
+
at = sp.end;
|
|
404
|
+
}
|
|
405
|
+
scan += unverbed.slice(at);
|
|
353
406
|
for (const tok of scan.trim().split(/\s+/)) {
|
|
354
407
|
if (!tok || tok[0] !== '-') continue;
|
|
355
408
|
if (tok.startsWith('--')) {
|
|
@@ -602,6 +655,7 @@ function extractUnansweredTail(cmd) {
|
|
|
602
655
|
if (c === quote) quote = null;
|
|
603
656
|
continue;
|
|
604
657
|
}
|
|
658
|
+
if (c === '\\') { i++; continue; } // outside quotes: escapes the next char (see firstShellClause)
|
|
605
659
|
if (c === '"' || c === "'") { quote = c; continue; }
|
|
606
660
|
if (c === ';' || (c === '&' && cmd[i + 1] === '&')) {
|
|
607
661
|
const tail = cmd.slice(i + (c === ';' ? 1 : 2)).trim();
|
|
@@ -695,6 +749,15 @@ function splitTopLevelSegments(cmd) {
|
|
|
695
749
|
if (c === quote) quote = null;
|
|
696
750
|
continue;
|
|
697
751
|
}
|
|
752
|
+
// Outside quotes: escapes the next char, kept verbatim (see firstShellClause)
|
|
753
|
+
// — except a newline, where the pair is a line continuation and the shell
|
|
754
|
+
// removes both. Keeping them left `&& \⏎ grep …` a segment that starts
|
|
755
|
+
// with `\`, which GREP_HEAD rejects (pre-ship review round 2 F1).
|
|
756
|
+
if (c === '\\' && i + 1 < cmd.length) {
|
|
757
|
+
if (cmd[i + 1] !== '\n') cur += c + cmd[i + 1];
|
|
758
|
+
i++;
|
|
759
|
+
continue;
|
|
760
|
+
}
|
|
698
761
|
if (c === '"' || c === "'") { quote = c; cur += c; continue; }
|
|
699
762
|
// `&&` and `||` (a single `&`/`|` is NOT a split — `|` is an output-filter
|
|
700
763
|
// pipe, lone `&` is background and rare in tool calls).
|
|
@@ -35,7 +35,7 @@ jobs:
|
|
|
35
35
|
node-version: '20'
|
|
36
36
|
- name: Build snapshot
|
|
37
37
|
run: |
|
|
38
|
-
npx -y -p @sdsrs/code-graph@0.
|
|
38
|
+
npx -y -p @sdsrs/code-graph@0.156.0 code-graph-mcp snapshot create --out snapshot.db
|
|
39
39
|
zstd -9 snapshot.db -o snapshot.db.zst
|
|
40
40
|
mv snapshot.db.zst "code-graph-snapshot-${GITHUB_SHA:0:7}.db.zst"
|
|
41
41
|
- name: Upload to release
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.156.0",
|
|
4
4
|
"description": "MCP server that indexes codebases into an AST knowledge graph with semantic search, call graph traversal, and HTTP route tracing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -35,10 +35,10 @@
|
|
|
35
35
|
"node": ">=16"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
|
-
"@sdsrs/code-graph-linux-x64": "0.
|
|
39
|
-
"@sdsrs/code-graph-linux-arm64": "0.
|
|
40
|
-
"@sdsrs/code-graph-darwin-x64": "0.
|
|
41
|
-
"@sdsrs/code-graph-darwin-arm64": "0.
|
|
42
|
-
"@sdsrs/code-graph-win32-x64": "0.
|
|
38
|
+
"@sdsrs/code-graph-linux-x64": "0.156.0",
|
|
39
|
+
"@sdsrs/code-graph-linux-arm64": "0.156.0",
|
|
40
|
+
"@sdsrs/code-graph-darwin-x64": "0.156.0",
|
|
41
|
+
"@sdsrs/code-graph-darwin-arm64": "0.156.0",
|
|
42
|
+
"@sdsrs/code-graph-win32-x64": "0.156.0"
|
|
43
43
|
}
|
|
44
44
|
}
|