@nanonets/graft 0.4.4 → 0.5.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.
- package/README.md +62 -19
- package/dist/ai/synthesize.d.ts.map +1 -1
- package/dist/ai/synthesize.js +1 -0
- package/dist/ai/synthesize.js.map +1 -1
- package/dist/ask/ask.d.ts +33 -0
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +105 -7
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/graphrank.d.ts.map +1 -1
- package/dist/ask/graphrank.js +1 -13
- package/dist/ask/graphrank.js.map +1 -1
- package/dist/claude/format.d.ts +17 -0
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +40 -1
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +16 -15
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +15 -5
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +4 -0
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-epilogue.d.ts +18 -0
- package/dist/cli-epilogue.d.ts.map +1 -0
- package/dist/cli-epilogue.js +61 -0
- package/dist/cli-epilogue.js.map +1 -0
- package/dist/cli-meta.d.ts +38 -0
- package/dist/cli-meta.d.ts.map +1 -0
- package/dist/cli-meta.js +127 -0
- package/dist/cli-meta.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +106 -4
- package/dist/cli.js.map +1 -1
- package/dist/engine.d.ts +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/graph/bindings.d.ts +42 -0
- package/dist/graph/bindings.d.ts.map +1 -0
- package/dist/graph/bindings.js +304 -0
- package/dist/graph/bindings.js.map +1 -0
- package/dist/graph/extract.d.ts +17 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +47 -5
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/map.d.ts +71 -0
- package/dist/graph/map.d.ts.map +1 -0
- package/dist/graph/map.js +150 -0
- package/dist/graph/map.js.map +1 -0
- package/dist/graph/relations.d.ts +14 -0
- package/dist/graph/relations.d.ts.map +1 -0
- package/dist/graph/relations.js +8 -0
- package/dist/graph/relations.js.map +1 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +0 -0
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/traverse.d.ts.map +1 -1
- package/dist/graph/traverse.js +1 -12
- package/dist/graph/traverse.js.map +1 -1
- package/dist/hosts/instructions.d.ts.map +1 -1
- package/dist/hosts/instructions.js +13 -6
- package/dist/hosts/instructions.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +80 -7
- package/dist/mcp/tools.js.map +1 -1
- package/dist/search/grep-cli.d.ts +32 -0
- package/dist/search/grep-cli.d.ts.map +1 -0
- package/dist/search/grep-cli.js +101 -0
- package/dist/search/grep-cli.js.map +1 -0
- package/dist/search/grep.d.ts +55 -0
- package/dist/search/grep.d.ts.map +1 -0
- package/dist/search/grep.js +126 -0
- package/dist/search/grep.js.map +1 -0
- package/dist/viewer/style.css +12 -12
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,eAAe,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"instructions.d.ts","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,eAAe,IAAI,MAAM,CAoCxC;AAED,wBAAgB,UAAU,IAAI,MAAM,CAOnC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAMrC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAGrC"}
|
|
@@ -11,14 +11,21 @@ system and carry exact file:line spans, kept in sync with the code through git.
|
|
|
11
11
|
For ANY task here — understanding how something works, finding where code lives,
|
|
12
12
|
or scoping a change — get context from the graph before grepping or opening
|
|
13
13
|
source files. Re-ask freely (it's cheap) and reuse literal identifiers you
|
|
14
|
-
already have (symbol, error string, file name) as the query.
|
|
14
|
+
already have (symbol, error string, file name) as the query. New to this repo?
|
|
15
|
+
Run \`graft map\` first — a token-budgeted orientation (dir clusters, hubs,
|
|
16
|
+
hotspots), no LLM, no key.
|
|
15
17
|
|
|
16
18
|
- Run \`graft ask "<your question>" --source\` → ranked nodes with the relevant
|
|
17
|
-
code spans inlined
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
code spans inlined (each hit's ≤8-line crux by default; \`--full\` for whole
|
|
20
|
+
definitions when the crux isn't enough). Match the tool to the task shape:
|
|
21
|
+
for understanding or editing, the top node IS the answer — cite its
|
|
22
|
+
\`covers:\` file:line spans and edit straight from \`--source\`. For
|
|
23
|
+
exhaustive tasks ("every occurrence / every caller of this pattern"), ranked
|
|
24
|
+
results are top-N, not complete — run \`graft grep "<literal>"\` instead
|
|
25
|
+
(exhaustive over indexed files, grouped by enclosing symbol), falling back
|
|
26
|
+
to raw \`grep -rn\` only for unindexed files.
|
|
27
|
+
- \`graft skeleton <file>\` → every definition's signature + span, ~10× cheaper
|
|
28
|
+
than reading the file; use it to skim an API surface.
|
|
22
29
|
- \`graft callers/callees <symbol>\` and \`graft impact <symbol> [-d N]\` give
|
|
23
30
|
precomputed, exact edges — who calls/is called by a symbol, and the full
|
|
24
31
|
blast radius — for structural questions, skip ranking and use these directly.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,eAAe;IAC7B,OAAO
|
|
1
|
+
{"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/hosts/instructions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,eAAe;IAC7B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkCQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO;;;;EAIP,eAAe,EAAE;CAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO;;;EAGP,eAAe,EAAE;CAClB,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,GAAG,eAAe,EAAE;CAC5B,CAAC;AACF,CAAC"}
|
package/dist/mcp/server.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function startMcpServer(root: string): void;
|
|
1
|
+
export declare function startMcpServer(root: string, dirOverride?: string): void;
|
|
2
2
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAmBA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAmBA,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CA8CvE"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -13,7 +13,7 @@ function reply(id, result) {
|
|
|
13
13
|
function replyError(id, code, message) {
|
|
14
14
|
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
15
15
|
}
|
|
16
|
-
export function startMcpServer(root) {
|
|
16
|
+
export function startMcpServer(root, dirOverride) {
|
|
17
17
|
const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
18
18
|
rl.on('line', (line) => {
|
|
19
19
|
const text = line.trim();
|
|
@@ -54,7 +54,7 @@ export function startMcpServer(root) {
|
|
|
54
54
|
return;
|
|
55
55
|
const name = String(params?.name ?? '');
|
|
56
56
|
const args = (params?.arguments ?? {});
|
|
57
|
-
const r = callTool(root, name, args);
|
|
57
|
+
const r = callTool(root, name, args, dirOverride);
|
|
58
58
|
reply(id, { content: [{ type: 'text', text: r.text }], isError: r.isError });
|
|
59
59
|
return;
|
|
60
60
|
}
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE7C,SAAS,IAAI,CAAC,GAAW;IACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,KAAK,CAAC,EAAW,EAAE,MAAc;IACxC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,UAAU,CAAC,EAAW,EAAE,IAAY,EAAE,OAAe;IAC5D,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAY;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export interface ToolDef {
|
|
|
4
4
|
inputSchema: object;
|
|
5
5
|
}
|
|
6
6
|
export declare const TOOLS: ToolDef[];
|
|
7
|
-
export declare function callTool(root: string, name: string, args: Record<string, unknown
|
|
7
|
+
export declare function callTool(root: string, name: string, args: Record<string, unknown>, dirOverride?: string): {
|
|
8
8
|
text: string;
|
|
9
9
|
isError: boolean;
|
|
10
10
|
};
|
package/dist/mcp/tools.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAiBA,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAWD,eAAO,MAAM,KAAK,EAAE,OAAO,EAmG1B,CAAC;AAiBF,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,CAAC,EAAE,MAAM,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAwFpC"}
|
package/dist/mcp/tools.js
CHANGED
|
@@ -3,13 +3,16 @@
|
|
|
3
3
|
* `callTool` never throws — hosts get soft errors as isError content.
|
|
4
4
|
*/
|
|
5
5
|
import { Graft } from '../engine.js';
|
|
6
|
-
import { formatAsk } from '../ask/ask.js';
|
|
6
|
+
import { formatAsk, skeleton, formatSkeleton } from '../ask/ask.js';
|
|
7
7
|
import { formatCheckReport } from '../context/check.js';
|
|
8
8
|
import { formatGraphCheckReport } from '../graph/check.js';
|
|
9
9
|
import { loadGraphCached } from '../graph/load.js';
|
|
10
10
|
import { contextDirFor } from '../context/node-file.js';
|
|
11
11
|
import { resolveSymbol, callersOf, calleesOf, impactOf, impactOfFile } from '../graph/traverse.js';
|
|
12
12
|
import { headerOf, hitLine, looseNoteFor } from '../graph/traverse-cli.js';
|
|
13
|
+
import { grepGraph } from '../search/grep.js';
|
|
14
|
+
import { formatGrepResult, zeroHitNote } from '../search/grep-cli.js';
|
|
15
|
+
import { buildRepoMap, formatRepoMap } from '../graph/map.js';
|
|
13
16
|
/** Default BFS depth for `graft_blast_radius`, same default as `graft impact`. */
|
|
14
17
|
const DEFAULT_BLAST_DEPTH = 2;
|
|
15
18
|
const NO_GRAPH = 'no graph found — run `graft build` first';
|
|
@@ -25,10 +28,25 @@ export const TOOLS = [
|
|
|
25
28
|
properties: {
|
|
26
29
|
query: { type: 'string', description: 'what you want to understand, in plain words' },
|
|
27
30
|
limit: { type: 'number', description: 'max results (default 5)' },
|
|
31
|
+
full: {
|
|
32
|
+
type: 'boolean',
|
|
33
|
+
description: 'inline whole definition spans instead of the default ≤8-line crux excerpts',
|
|
34
|
+
},
|
|
28
35
|
},
|
|
29
36
|
required: ['query'],
|
|
30
37
|
},
|
|
31
38
|
},
|
|
39
|
+
{
|
|
40
|
+
name: 'graft_skeleton',
|
|
41
|
+
description: "Signatures-only view of one file — every definition's signature + line span, ~10× cheaper than reading the file ($0, no LLM).",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
file: { type: 'string', description: 'repo-relative path (or unique basename) of the file' },
|
|
46
|
+
},
|
|
47
|
+
required: ['file'],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
32
50
|
{
|
|
33
51
|
name: 'graft_check',
|
|
34
52
|
description: 'Report whether the committed graph is in sync with the code (drift check).',
|
|
@@ -71,6 +89,30 @@ export const TOOLS = [
|
|
|
71
89
|
required: ['symbol'],
|
|
72
90
|
},
|
|
73
91
|
},
|
|
92
|
+
{
|
|
93
|
+
name: 'graft_grep',
|
|
94
|
+
description: 'Regex search over the graph\'s indexed files, hits grouped by innermost enclosing symbol and ranked by incoming-edge count (coupling) — which hit matters, not just where it is.',
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: 'object',
|
|
97
|
+
properties: {
|
|
98
|
+
pattern: { type: 'string', description: 'regex pattern (or literal string with fixed: true)' },
|
|
99
|
+
in: { type: 'string', description: 'narrow to files whose path contains this substring' },
|
|
100
|
+
ignore_case: { type: 'boolean', description: 'case-insensitive match' },
|
|
101
|
+
fixed: { type: 'boolean', description: 'treat pattern as a literal string, not a regex' },
|
|
102
|
+
},
|
|
103
|
+
required: ['pattern'],
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'graft_map',
|
|
108
|
+
description: 'Token-budgeted repo orientation — directory clusters, per-directory hubs, and global hotspots computed purely from the wiring graph ($0, no LLM). Use this to get oriented in an unfamiliar repo before diving into files.',
|
|
109
|
+
inputSchema: {
|
|
110
|
+
type: 'object',
|
|
111
|
+
properties: {
|
|
112
|
+
max_dirs: { type: 'number', description: 'max directory entries shown, rest counted into dropped (default 16)' },
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
74
116
|
];
|
|
75
117
|
/** Render every resolved match's header + edge report (or the loud zero-edge
|
|
76
118
|
* note), one block per match, joined with a blank line — the same grouping
|
|
@@ -89,7 +131,7 @@ function renderMatches(kind, matches, hitsFor) {
|
|
|
89
131
|
})
|
|
90
132
|
.join('\n\n');
|
|
91
133
|
}
|
|
92
|
-
export function callTool(root, name, args) {
|
|
134
|
+
export function callTool(root, name, args, dirOverride) {
|
|
93
135
|
try {
|
|
94
136
|
switch (name) {
|
|
95
137
|
case 'graft_ask': {
|
|
@@ -97,12 +139,19 @@ export function callTool(root, name, args) {
|
|
|
97
139
|
if (!query)
|
|
98
140
|
return { text: 'graft_ask requires a query', isError: true };
|
|
99
141
|
const limit = typeof args.limit === 'number' ? args.limit : 5;
|
|
100
|
-
const engine = new Graft();
|
|
101
|
-
const r = engine.ask(root, query, { limit, source: true });
|
|
142
|
+
const engine = new Graft({ contextDir: dirOverride });
|
|
143
|
+
const r = engine.ask(root, query, { limit, source: true, full: args.full === true });
|
|
102
144
|
return { text: formatAsk(r), isError: false };
|
|
103
145
|
}
|
|
146
|
+
case 'graft_skeleton': {
|
|
147
|
+
const file = String(args.file ?? '');
|
|
148
|
+
if (!file)
|
|
149
|
+
return { text: 'graft_skeleton requires a file', isError: true };
|
|
150
|
+
const r = skeleton(root, file, { contextDir: dirOverride });
|
|
151
|
+
return { text: formatSkeleton(r), isError: !r.entries.length && !!r.note };
|
|
152
|
+
}
|
|
104
153
|
case 'graft_check': {
|
|
105
|
-
const engine = new Graft();
|
|
154
|
+
const engine = new Graft({ contextDir: dirOverride });
|
|
106
155
|
const r = engine.check(root);
|
|
107
156
|
const g = engine.checkGraph(root);
|
|
108
157
|
const parts = [formatCheckReport(r)];
|
|
@@ -114,7 +163,7 @@ export function callTool(root, name, args) {
|
|
|
114
163
|
const query = String(args.symbol ?? args.file ?? '');
|
|
115
164
|
if (!query)
|
|
116
165
|
return { text: 'graft_blast_radius requires a file or symbol', isError: true };
|
|
117
|
-
const w = loadGraphCached(contextDirFor(root));
|
|
166
|
+
const w = loadGraphCached(contextDirFor(root, dirOverride));
|
|
118
167
|
if (!w)
|
|
119
168
|
return { text: NO_GRAPH, isError: true };
|
|
120
169
|
const matches = resolveSymbol(w, query);
|
|
@@ -138,7 +187,7 @@ export function callTool(root, name, args) {
|
|
|
138
187
|
const symbol = String(args.symbol ?? '');
|
|
139
188
|
if (!symbol)
|
|
140
189
|
return { text: `${name} requires a symbol`, isError: true };
|
|
141
|
-
const w = loadGraphCached(contextDirFor(root));
|
|
190
|
+
const w = loadGraphCached(contextDirFor(root, dirOverride));
|
|
142
191
|
if (!w)
|
|
143
192
|
return { text: NO_GRAPH, isError: true };
|
|
144
193
|
const inOpt = typeof args.in === 'string' && args.in ? { in: args.in } : {};
|
|
@@ -150,6 +199,30 @@ export function callTool(root, name, args) {
|
|
|
150
199
|
const text = renderMatches(kind, matches, (m) => walk(w, m));
|
|
151
200
|
return { text, isError: false };
|
|
152
201
|
}
|
|
202
|
+
case 'graft_grep': {
|
|
203
|
+
const pattern = String(args.pattern ?? '');
|
|
204
|
+
if (!pattern)
|
|
205
|
+
return { text: 'graft_grep requires a pattern', isError: true };
|
|
206
|
+
const w = loadGraphCached(contextDirFor(root, dirOverride));
|
|
207
|
+
if (!w)
|
|
208
|
+
return { text: NO_GRAPH, isError: true };
|
|
209
|
+
const result = grepGraph(w, root, pattern, {
|
|
210
|
+
ignoreCase: typeof args.ignore_case === 'boolean' ? args.ignore_case : undefined,
|
|
211
|
+
fixed: typeof args.fixed === 'boolean' ? args.fixed : undefined,
|
|
212
|
+
in: typeof args.in === 'string' && args.in ? args.in : undefined,
|
|
213
|
+
});
|
|
214
|
+
if (result.totalHits === 0)
|
|
215
|
+
return { text: zeroHitNote(result), isError: false };
|
|
216
|
+
return { text: formatGrepResult(result), isError: false };
|
|
217
|
+
}
|
|
218
|
+
case 'graft_map': {
|
|
219
|
+
const w = loadGraphCached(contextDirFor(root, dirOverride));
|
|
220
|
+
if (!w)
|
|
221
|
+
return { text: NO_GRAPH, isError: true };
|
|
222
|
+
const maxDirs = typeof args.max_dirs === 'number' && Number.isFinite(args.max_dirs) && args.max_dirs > 0 ? args.max_dirs : undefined;
|
|
223
|
+
const map = buildRepoMap(w, { maxDirs });
|
|
224
|
+
return { text: formatRepoMap(map), isError: false };
|
|
225
|
+
}
|
|
153
226
|
default:
|
|
154
227
|
return { text: `unknown tool: ${name}`, isError: true };
|
|
155
228
|
}
|
package/dist/mcp/tools.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/mcp/tools.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAgB,MAAM,sBAAsB,CAAC;AACjH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAqB,MAAM,0BAA0B,CAAC;AAC9F,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAS9D,kFAAkF;AAClF,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B,MAAM,QAAQ,GAAG,0CAA0C,CAAC;AAE5D,SAAS,iBAAiB,CAAC,KAAa;IACtC,OAAO,cAAc,KAAK,wDAAwD,CAAC;AACrF,CAAC;AAED,MAAM,CAAC,MAAM,KAAK,GAAc;IAC9B;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,+KAA+K;QACjL,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,6CAA6C,EAAE;gBACrF,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,yBAAyB,EAAE;gBACjE,IAAI,EAAE;oBACJ,IAAI,EAAE,SAAS;oBACf,WAAW,EAAE,4EAA4E;iBAC1F;aACF;YACD,QAAQ,EAAE,CAAC,OAAO,CAAC;SACpB;KACF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,WAAW,EACT,+HAA+H;QACjI,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qDAAqD,EAAE;aAC7F;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;SACnB;KACF;IACD;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,4EAA4E;QACzF,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE;KAChD;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,iIAAiI;QACnI,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,mFAAmF,EAAE;gBAC1H,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,+EAA+E,EAAE;gBACxH,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;aACpE;YACD,QAAQ,EAAE,CAAC,MAAM,CAAC;SACnB;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,iFAAiF;QAC9F,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE;gBAC7G,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4DAA4D,EAAE;aAClG;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,kFAAkF;QAC/F,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oEAAoE,EAAE;gBAC7G,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4DAA4D,EAAE;aAClG;YACD,QAAQ,EAAE,CAAC,QAAQ,CAAC;SACrB;KACF;IACD;QACE,IAAI,EAAE,YAAY;QAClB,WAAW,EACT,kLAAkL;QACpL,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oDAAoD,EAAE;gBAC9F,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oDAAoD,EAAE;gBACzF,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,wBAAwB,EAAE;gBACvE,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,gDAAgD,EAAE;aAC1F;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;SACtB;KACF;IACD;QACE,IAAI,EAAE,WAAW;QACjB,WAAW,EACT,4NAA4N;QAC9N,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qEAAqE,EAAE;aACjH;SACF;KACF;CACF,CAAC;AAEF;;qEAEqE;AACrE,SAAS,aAAa,CAAC,IAAkB,EAAE,OAAiB,EAAE,OAAiC;IAC7F,OAAO,OAAO;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,KAAK,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;;YACzD,KAAK,MAAM,CAAC,IAAI,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;SACD,IAAI,CAAC,MAAM,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,IAAY,EACZ,IAAY,EACZ,IAA6B,EAC7B,WAAoB;IAEpB,IAAI,CAAC;QACH,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBACvC,IAAI,CAAC,KAAK;oBAAE,OAAO,EAAE,IAAI,EAAE,4BAA4B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACzE,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC9D,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;gBACtD,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;gBACrF,OAAO,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAChD,CAAC;YACD,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACtB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBACrC,IAAI,CAAC,IAAI;oBAAE,OAAO,EAAE,IAAI,EAAE,gCAAgC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAC5E,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;gBAC5D,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAC7E,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;gBACtD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC7B,MAAM,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;gBAClC,MAAM,KAAK,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;gBACrC,IAAI,CAAC,CAAC,CAAC,OAAO;oBAAE,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;gBACtD,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtD,CAAC;YACD,KAAK,oBAAoB,CAAC,CAAC,CAAC;gBAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;gBACrD,IAAI,CAAC,KAAK;oBAAE,OAAO,EAAE,IAAI,EAAE,8CAA8C,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAC3F,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC5D,IAAI,CAAC,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;gBACxC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACnF,MAAM,KAAK,GACT,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC;oBAC9E,CAAC,CAAC,IAAI,CAAC,KAAK;oBACZ,CAAC,CAAC,mBAAmB,CAAC;gBAC1B,4EAA4E;gBAC5E,uEAAuE;gBACvE,sEAAsE;gBACtE,mEAAmE;gBACnE,kEAAkE;gBAClE,oEAAoE;gBACpE,8BAA8B;gBAC9B,MAAM,IAAI,GAAG,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAClD,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CACtE,CAAC;gBACF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAClC,CAAC;YACD,KAAK,eAAe,CAAC;YACrB,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;gBACzC,IAAI,CAAC,MAAM;oBAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACzE,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC5D,IAAI,CAAC,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;gBAChD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACpF,MAAM,IAAI,GAAiB,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;gBAC5E,MAAM,IAAI,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;gBACxD,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC7D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAClC,CAAC;YACD,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;gBAC3C,IAAI,CAAC,OAAO;oBAAE,OAAO,EAAE,IAAI,EAAE,+BAA+B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBAC9E,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC5D,IAAI,CAAC,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACjD,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;oBACzC,UAAU,EAAE,OAAO,IAAI,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;oBAChF,KAAK,EAAE,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;oBAC/D,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;iBACjE,CAAC,CAAC;gBACH,IAAI,MAAM,CAAC,SAAS,KAAK,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;gBACjF,OAAO,EAAE,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YAC5D,CAAC;YACD,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;gBAC5D,IAAI,CAAC,CAAC;oBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;gBACjD,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrI,MAAM,GAAG,GAAG,YAAY,CAAC,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;gBACzC,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;YACtD,CAAC;YACD;gBACE,OAAO,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC5D,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,IAAI,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACnF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type GrepResult } from "./grep.js";
|
|
2
|
+
export interface GrepCliOptions {
|
|
3
|
+
ignoreCase?: boolean;
|
|
4
|
+
fixed?: boolean;
|
|
5
|
+
in?: string;
|
|
6
|
+
json?: boolean;
|
|
7
|
+
/** the top-level `--dir` override, so this command respects it like every other. */
|
|
8
|
+
globalDir?: string;
|
|
9
|
+
}
|
|
10
|
+
/** `"<pattern>" — N hits in M symbols across K files (searched T indexed files)` */
|
|
11
|
+
export declare function formatGrepHeader(result: GrepResult): string;
|
|
12
|
+
/** Full human report: header, blank line, then one block per group (header +
|
|
13
|
+
* indented hit lines), each block separated by a blank line. */
|
|
14
|
+
export declare function formatGrepResult(result: GrepResult): string;
|
|
15
|
+
/** Loud, actionable zero-hit note (never a bare empty result) — printed to
|
|
16
|
+
* stderr; the caller still exits 0, since "no hits in the indexed graph" is
|
|
17
|
+
* not an error, just a reason to fall back to a real grep.
|
|
18
|
+
*
|
|
19
|
+
* Truncation is never silent, even on the zero-hit path: if some indexed
|
|
20
|
+
* files couldn't be read (`truncated.files > 0`), that's called out too —
|
|
21
|
+
* otherwise a zero-hit result on a stale graph or wrong root reads as "no
|
|
22
|
+
* matches" when really some files were never searched at all. */
|
|
23
|
+
export declare function zeroHitNote(result: GrepResult): string;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the graph at `dir` (respecting `--dir`), run `grepGraph`, and print
|
|
26
|
+
* either the human report or `--json`. Exits the process (code 1) when
|
|
27
|
+
* there's no graph at all or the pattern fails to compile as a regex — both
|
|
28
|
+
* are caller-facing mistakes, not recoverable states. Zero hits is NOT an
|
|
29
|
+
* error: it prints a loud note to stderr and exits 0.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runGrepCommand(pattern: string, dir: string, opts: GrepCliOptions): void;
|
|
32
|
+
//# sourceMappingURL=grep-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep-cli.d.ts","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"AAYA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3D;AAYD;gEACgE;AAChE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAM3D;AAED;;;;;;;iEAOiE;AACjE,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAKtD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA6BvF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI wiring + human formatter for `graft grep`.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of cli.ts (argument wiring only) and out of grep.ts (pure core,
|
|
5
|
+
* unit-testable against hand-built fixture graphs without touching a real
|
|
6
|
+
* repo root) — same split as traverse.ts/traverse-cli.ts. `formatGrepResult`
|
|
7
|
+
* is exported so `graft_grep` in `src/mcp/tools.ts` renders the identical
|
|
8
|
+
* report, rather than re-implementing it.
|
|
9
|
+
*/
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { contextDirFor } from "../context/node-file.js";
|
|
12
|
+
import { loadGraphCached } from "../graph/load.js";
|
|
13
|
+
import { grepGraph } from "./grep.js";
|
|
14
|
+
function groupHeader(g) {
|
|
15
|
+
if (g.symbol)
|
|
16
|
+
return `${g.symbol.name} · ${g.symbol.kind} · ${g.symbol.path}:${g.symbol.span} · ${g.inDegree} in-edges`;
|
|
17
|
+
return `${g.path} (module level) · ${g.inDegree} in-edges`;
|
|
18
|
+
}
|
|
19
|
+
function formatGroup(g) {
|
|
20
|
+
const lines = [groupHeader(g)];
|
|
21
|
+
for (const h of g.hits)
|
|
22
|
+
lines.push(` L${h.line}: ${h.text}`);
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
/** `"<pattern>" — N hits in M symbols across K files (searched T indexed files)` */
|
|
26
|
+
export function formatGrepHeader(result) {
|
|
27
|
+
const filesHit = new Set(result.groups.map((g) => g.path)).size;
|
|
28
|
+
return `"${result.pattern}" — ${result.totalHits} hits in ${result.groups.length} symbols across ${filesHit} files (searched ${result.filesSearched} indexed files)`;
|
|
29
|
+
}
|
|
30
|
+
/** Loud truncation note — dropped counts are never silent. */
|
|
31
|
+
function truncationNote(result) {
|
|
32
|
+
const { files, hits } = result.truncated;
|
|
33
|
+
if (files === 0 && hits === 0)
|
|
34
|
+
return null;
|
|
35
|
+
const parts = [];
|
|
36
|
+
if (hits > 0)
|
|
37
|
+
parts.push(`${hits} more hit${hits === 1 ? "" : "s"} beyond the cap`);
|
|
38
|
+
if (files > 0)
|
|
39
|
+
parts.push(`${files} indexed file${files === 1 ? "" : "s"} unreadable`);
|
|
40
|
+
return `(truncated: ${parts.join(", ")} — narrow with --in or refine the pattern)`;
|
|
41
|
+
}
|
|
42
|
+
/** Full human report: header, blank line, then one block per group (header +
|
|
43
|
+
* indented hit lines), each block separated by a blank line. */
|
|
44
|
+
export function formatGrepResult(result) {
|
|
45
|
+
const blocks = [formatGrepHeader(result), "", ...result.groups.map((g) => formatGroup(g) + "\n")];
|
|
46
|
+
let out = blocks.join("\n").replace(/\n+$/, "\n");
|
|
47
|
+
const note = truncationNote(result);
|
|
48
|
+
if (note)
|
|
49
|
+
out += note + "\n";
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Loud, actionable zero-hit note (never a bare empty result) — printed to
|
|
53
|
+
* stderr; the caller still exits 0, since "no hits in the indexed graph" is
|
|
54
|
+
* not an error, just a reason to fall back to a real grep.
|
|
55
|
+
*
|
|
56
|
+
* Truncation is never silent, even on the zero-hit path: if some indexed
|
|
57
|
+
* files couldn't be read (`truncated.files > 0`), that's called out too —
|
|
58
|
+
* otherwise a zero-hit result on a stale graph or wrong root reads as "no
|
|
59
|
+
* matches" when really some files were never searched at all. */
|
|
60
|
+
export function zeroHitNote(result) {
|
|
61
|
+
const base = `no hits for "${result.pattern}" in ${result.filesSearched} indexed files — unindexed files (docs, configs, new files) aren't searched; try grep -rn "${result.pattern}" for those`;
|
|
62
|
+
const { files } = result.truncated;
|
|
63
|
+
if (files === 0)
|
|
64
|
+
return base;
|
|
65
|
+
return `${base} — note: ${files} indexed file${files === 1 ? "" : "s"} could not be read (stale graph? run graft build)`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the graph at `dir` (respecting `--dir`), run `grepGraph`, and print
|
|
69
|
+
* either the human report or `--json`. Exits the process (code 1) when
|
|
70
|
+
* there's no graph at all or the pattern fails to compile as a regex — both
|
|
71
|
+
* are caller-facing mistakes, not recoverable states. Zero hits is NOT an
|
|
72
|
+
* error: it prints a loud note to stderr and exits 0.
|
|
73
|
+
*/
|
|
74
|
+
export function runGrepCommand(pattern, dir, opts) {
|
|
75
|
+
const root = resolve(dir);
|
|
76
|
+
const contextDir = contextDirFor(root, opts.globalDir);
|
|
77
|
+
const graph = loadGraphCached(contextDir);
|
|
78
|
+
if (!graph) {
|
|
79
|
+
console.error("✗ no graph — run graft build first");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
let result;
|
|
83
|
+
try {
|
|
84
|
+
result = grepGraph(graph, root, pattern, { ignoreCase: opts.ignoreCase, fixed: opts.fixed, in: opts.in });
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error(`✗ invalid pattern "${pattern}": ${err instanceof Error ? err.message : String(err)}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (opts.json) {
|
|
92
|
+
console.log(JSON.stringify(result, null, 2));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (result.totalHits === 0) {
|
|
96
|
+
console.error(zeroHitNote(result));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write(formatGrepResult(result));
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=grep-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep-cli.js","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAmC,MAAM,WAAW,CAAC;AAWvE,SAAS,WAAW,CAAC,CAAY;IAC/B,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,CAAC,QAAQ,WAAW,CAAC;IACxH,OAAO,GAAG,CAAC,CAAC,IAAI,qBAAqB,CAAC,CAAC,QAAQ,WAAW,CAAC;AAC7D,CAAC;AAED,SAAS,WAAW,CAAC,CAAY;IAC/B,MAAM,KAAK,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI;QAAE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,OAAO,IAAI,MAAM,CAAC,OAAO,OAAO,MAAM,CAAC,SAAS,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,mBAAmB,QAAQ,oBAAoB,MAAM,CAAC,aAAa,iBAAiB,CAAC;AACvK,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAC,MAAkB;IACxC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IACzC,IAAI,KAAK,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,IAAI,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,YAAY,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC;IACpF,IAAI,KAAK,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC;IACvF,OAAO,eAAe,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,4CAA4C,CAAC;AACrF,CAAC;AAED;gEACgE;AAChE,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,MAAM,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAClG,IAAI,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACpC,IAAI,IAAI;QAAE,GAAG,IAAI,IAAI,GAAG,IAAI,CAAC;IAC7B,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;iEAOiE;AACjE,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,MAAM,IAAI,GAAG,gBAAgB,MAAM,CAAC,OAAO,QAAQ,MAAM,CAAC,aAAa,8FAA8F,MAAM,CAAC,OAAO,aAAa,CAAC;IACjM,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC;IACnC,IAAI,KAAK,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7B,OAAO,GAAG,IAAI,YAAY,KAAK,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,mDAAmD,CAAC;AAC3H,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,GAAW,EAAE,IAAoB;IAC/E,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1B,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,MAAkB,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5G,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,OAAO;IACT,CAAC;IAED,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,IAAI,MAAM,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;QACnC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GraphV1 } from "../graph/types.js";
|
|
2
|
+
export interface GrepHit {
|
|
3
|
+
line: number;
|
|
4
|
+
/** Trimmed line text, capped at 160 chars. */
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GrepSymbolRef {
|
|
8
|
+
id: string;
|
|
9
|
+
/** Qualified scope-joined name (e.g. `FastAPI.include_router`), not just
|
|
10
|
+
* the bare symbol name — the id's segment after the file-path `#`. */
|
|
11
|
+
name: string;
|
|
12
|
+
kind: string;
|
|
13
|
+
path: string;
|
|
14
|
+
span: string;
|
|
15
|
+
}
|
|
16
|
+
export interface GrepGroup {
|
|
17
|
+
/** null → file-level: the hit lies outside every indexed symbol's span
|
|
18
|
+
* (module-level code — imports, top-level statements, module constants). */
|
|
19
|
+
symbol: GrepSymbolRef | null;
|
|
20
|
+
path: string;
|
|
21
|
+
/** Incoming WALK_RELATIONS edges targeting the symbol — always 0 for
|
|
22
|
+
* file-level groups (there's no single symbol id to count edges against). */
|
|
23
|
+
inDegree: number;
|
|
24
|
+
hits: GrepHit[];
|
|
25
|
+
}
|
|
26
|
+
export interface GrepResult {
|
|
27
|
+
pattern: string;
|
|
28
|
+
/** Indexed file nodes considered (after the `in` filter), whether or not
|
|
29
|
+
* each was actually readable — matches the CLI's "searched N indexed
|
|
30
|
+
* files" wording. */
|
|
31
|
+
filesSearched: number;
|
|
32
|
+
/** Hits actually collected (<= maxHits). */
|
|
33
|
+
totalHits: number;
|
|
34
|
+
/** Sorted: inDegree desc, then path asc. */
|
|
35
|
+
groups: GrepGroup[];
|
|
36
|
+
/** Dropped counts — never silent. `files`: indexed file nodes that
|
|
37
|
+
* couldn't be read from disk. `hits`: matches found beyond `maxHits`,
|
|
38
|
+
* counted but not collected. */
|
|
39
|
+
truncated: {
|
|
40
|
+
files: number;
|
|
41
|
+
hits: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface GrepOptions {
|
|
45
|
+
ignoreCase?: boolean;
|
|
46
|
+
/** Treat `pattern` as a literal string (regex-escaped), not a regex. */
|
|
47
|
+
fixed?: boolean;
|
|
48
|
+
/** Narrow to file nodes whose path contains this substring. */
|
|
49
|
+
in?: string;
|
|
50
|
+
/** Stop collecting hits after this many; the rest are tallied into
|
|
51
|
+
* `truncated.hits`. Default 300. */
|
|
52
|
+
maxHits?: number;
|
|
53
|
+
}
|
|
54
|
+
export declare function grepGraph(graph: GraphV1, repoRoot: string, pattern: string, opts?: GrepOptions): GrepResult;
|
|
55
|
+
//# sourceMappingURL=grep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/search/grep.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAU,MAAM,mBAAmB,CAAC;AAGzD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX;0EACsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB;gFAC4E;IAC5E,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb;iFAC6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB;;yBAEqB;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;oCAEgC;IAChC,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;wCACoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,UAAU,CA8D/G"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graft grep` core: regex search over the graph's indexed files, with hits
|
|
3
|
+
* grouped by their innermost enclosing symbol and ranked by incoming-edge
|
|
4
|
+
* count (coupling) — a grep that answers "which of these hits matters",
|
|
5
|
+
* because plain `grep -rn` gives no way to tell a hit inside a
|
|
6
|
+
* heavily-depended-on function from one inside dead code.
|
|
7
|
+
*
|
|
8
|
+
* Pure I/O + regex, no CLI/MCP concerns: `grep-cli.ts` formats this into
|
|
9
|
+
* human text and wires the CLI command; `mcp/tools.ts` renders the same
|
|
10
|
+
* shape for the `graft_grep` tool.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { WALK_RELATIONS } from "../graph/relations.js";
|
|
15
|
+
const DEFAULT_MAX_HITS = 300;
|
|
16
|
+
const MAX_HIT_TEXT = 160;
|
|
17
|
+
const SPAN_RE = /^L(\d+)-L(\d+)$/;
|
|
18
|
+
function escapeRegExp(s) {
|
|
19
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20
|
+
}
|
|
21
|
+
function spanBounds(span) {
|
|
22
|
+
const m = SPAN_RE.exec(span);
|
|
23
|
+
if (!m)
|
|
24
|
+
return null;
|
|
25
|
+
return { start: Number(m[1]), end: Number(m[2]) };
|
|
26
|
+
}
|
|
27
|
+
/** The file's symbol nodes, sorted ascending by span start — the order
|
|
28
|
+
* `enclosingSymbol` scans in to find the innermost containing span. */
|
|
29
|
+
function symbolsOf(graph, path) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const n of graph.nodes) {
|
|
32
|
+
if (n.kind === "file" || n.path !== path)
|
|
33
|
+
continue;
|
|
34
|
+
const b = spanBounds(n.span);
|
|
35
|
+
if (b)
|
|
36
|
+
out.push({ node: n, start: b.start, end: b.end });
|
|
37
|
+
}
|
|
38
|
+
out.sort((a, b) => a.start - b.start);
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** Innermost symbol containing `line`: among spans that contain it, the one
|
|
42
|
+
* with the greatest start line. Symbols are pre-sorted ascending by start,
|
|
43
|
+
* so the last containing match seen wins, and the scan can stop as soon as
|
|
44
|
+
* a span starts after `line` — nothing later in the sort can contain it. */
|
|
45
|
+
function enclosingSymbol(symbols, line) {
|
|
46
|
+
let found = null;
|
|
47
|
+
for (const s of symbols) {
|
|
48
|
+
if (s.start > line)
|
|
49
|
+
break;
|
|
50
|
+
if (line <= s.end)
|
|
51
|
+
found = s.node;
|
|
52
|
+
}
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
55
|
+
/** Incoming WALK_RELATIONS edge count per target id — one pass over
|
|
56
|
+
* `graph.edges`, computed once per call and shared across every hit. */
|
|
57
|
+
function computeInDegree(graph) {
|
|
58
|
+
const deg = new Map();
|
|
59
|
+
for (const e of graph.edges) {
|
|
60
|
+
if (!WALK_RELATIONS.has(e.relation))
|
|
61
|
+
continue;
|
|
62
|
+
deg.set(e.target, (deg.get(e.target) ?? 0) + 1);
|
|
63
|
+
}
|
|
64
|
+
return deg;
|
|
65
|
+
}
|
|
66
|
+
function toSymbolRef(n) {
|
|
67
|
+
const hash = n.id.indexOf("#");
|
|
68
|
+
return { id: n.id, name: hash >= 0 ? n.id.slice(hash + 1) : n.name, kind: n.kind, path: n.path, span: n.span };
|
|
69
|
+
}
|
|
70
|
+
export function grepGraph(graph, repoRoot, pattern, opts = {}) {
|
|
71
|
+
const maxHits = opts.maxHits ?? DEFAULT_MAX_HITS;
|
|
72
|
+
const source = opts.fixed ? escapeRegExp(pattern) : pattern;
|
|
73
|
+
const regex = new RegExp(source, opts.ignoreCase ? "i" : "");
|
|
74
|
+
const inDegree = computeInDegree(graph);
|
|
75
|
+
const fileNodes = graph.nodes.filter((n) => n.kind === "file" && (!opts.in || n.path.includes(opts.in)));
|
|
76
|
+
const groups = new Map();
|
|
77
|
+
let collected = 0;
|
|
78
|
+
let truncatedHits = 0;
|
|
79
|
+
let truncatedFiles = 0;
|
|
80
|
+
for (const file of fileNodes) {
|
|
81
|
+
let text;
|
|
82
|
+
try {
|
|
83
|
+
text = readFileSync(join(repoRoot, file.path), "utf8");
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
truncatedFiles++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const symbols = symbolsOf(graph, file.path);
|
|
90
|
+
const lines = text.split("\n");
|
|
91
|
+
for (let i = 0; i < lines.length; i++) {
|
|
92
|
+
const raw = lines[i];
|
|
93
|
+
if (!regex.test(raw))
|
|
94
|
+
continue;
|
|
95
|
+
if (collected >= maxHits) {
|
|
96
|
+
truncatedHits++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
collected++;
|
|
100
|
+
const lineNo = i + 1;
|
|
101
|
+
const sym = enclosingSymbol(symbols, lineNo);
|
|
102
|
+
const key = sym ? sym.id : `file:${file.path}`;
|
|
103
|
+
let group = groups.get(key);
|
|
104
|
+
if (!group) {
|
|
105
|
+
group = {
|
|
106
|
+
symbol: sym ? toSymbolRef(sym) : null,
|
|
107
|
+
path: file.path,
|
|
108
|
+
inDegree: sym ? (inDegree.get(sym.id) ?? 0) : 0,
|
|
109
|
+
hits: [],
|
|
110
|
+
};
|
|
111
|
+
groups.set(key, group);
|
|
112
|
+
}
|
|
113
|
+
const trimmed = raw.trim();
|
|
114
|
+
group.hits.push({ line: lineNo, text: trimmed.length > MAX_HIT_TEXT ? trimmed.slice(0, MAX_HIT_TEXT) : trimmed });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const sortedGroups = [...groups.values()].sort((a, b) => b.inDegree - a.inDegree || a.path.localeCompare(b.path));
|
|
118
|
+
return {
|
|
119
|
+
pattern,
|
|
120
|
+
filesSearched: fileNodes.length,
|
|
121
|
+
totalHits: collected,
|
|
122
|
+
groups: sortedGroups,
|
|
123
|
+
truncated: { files: truncatedFiles, hits: truncatedHits },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=grep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../src/search/grep.ts"],"names":[],"mappings":"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"}
|