@nanonets/graft 0.4.5 → 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.
Files changed (75) hide show
  1. package/README.md +58 -12
  2. package/dist/ai/synthesize.d.ts.map +1 -1
  3. package/dist/ai/synthesize.js +1 -0
  4. package/dist/ai/synthesize.js.map +1 -1
  5. package/dist/ask/ask.d.ts +33 -0
  6. package/dist/ask/ask.d.ts.map +1 -1
  7. package/dist/ask/ask.js +105 -7
  8. package/dist/ask/ask.js.map +1 -1
  9. package/dist/ask/graphrank.d.ts.map +1 -1
  10. package/dist/ask/graphrank.js +1 -13
  11. package/dist/ask/graphrank.js.map +1 -1
  12. package/dist/claude/format.d.ts +17 -0
  13. package/dist/claude/format.d.ts.map +1 -1
  14. package/dist/claude/format.js +40 -1
  15. package/dist/claude/format.js.map +1 -1
  16. package/dist/claude/hooks.d.ts.map +1 -1
  17. package/dist/claude/hooks.js +16 -15
  18. package/dist/claude/hooks.js.map +1 -1
  19. package/dist/claude/skill-template.d.ts.map +1 -1
  20. package/dist/claude/skill-template.js +15 -5
  21. package/dist/claude/skill-template.js.map +1 -1
  22. package/dist/claude/state.d.ts +4 -0
  23. package/dist/claude/state.d.ts.map +1 -1
  24. package/dist/claude/state.js +1 -1
  25. package/dist/claude/state.js.map +1 -1
  26. package/dist/cli.d.ts +2 -0
  27. package/dist/cli.d.ts.map +1 -1
  28. package/dist/cli.js +75 -2
  29. package/dist/cli.js.map +1 -1
  30. package/dist/engine.d.ts +1 -0
  31. package/dist/engine.d.ts.map +1 -1
  32. package/dist/engine.js +1 -1
  33. package/dist/engine.js.map +1 -1
  34. package/dist/graph/bindings.d.ts +42 -0
  35. package/dist/graph/bindings.d.ts.map +1 -0
  36. package/dist/graph/bindings.js +304 -0
  37. package/dist/graph/bindings.js.map +1 -0
  38. package/dist/graph/extract.d.ts +17 -1
  39. package/dist/graph/extract.d.ts.map +1 -1
  40. package/dist/graph/extract.js +47 -5
  41. package/dist/graph/extract.js.map +1 -1
  42. package/dist/graph/map.d.ts +71 -0
  43. package/dist/graph/map.d.ts.map +1 -0
  44. package/dist/graph/map.js +150 -0
  45. package/dist/graph/map.js.map +1 -0
  46. package/dist/graph/relations.d.ts +14 -0
  47. package/dist/graph/relations.d.ts.map +1 -0
  48. package/dist/graph/relations.js +8 -0
  49. package/dist/graph/relations.js.map +1 -0
  50. package/dist/graph/resolve.d.ts.map +1 -1
  51. package/dist/graph/resolve.js +0 -0
  52. package/dist/graph/resolve.js.map +1 -1
  53. package/dist/graph/traverse.d.ts.map +1 -1
  54. package/dist/graph/traverse.js +1 -12
  55. package/dist/graph/traverse.js.map +1 -1
  56. package/dist/hosts/instructions.d.ts.map +1 -1
  57. package/dist/hosts/instructions.js +13 -6
  58. package/dist/hosts/instructions.js.map +1 -1
  59. package/dist/mcp/server.d.ts +1 -1
  60. package/dist/mcp/server.d.ts.map +1 -1
  61. package/dist/mcp/server.js +2 -2
  62. package/dist/mcp/server.js.map +1 -1
  63. package/dist/mcp/tools.d.ts +1 -1
  64. package/dist/mcp/tools.d.ts.map +1 -1
  65. package/dist/mcp/tools.js +80 -7
  66. package/dist/mcp/tools.js.map +1 -1
  67. package/dist/search/grep-cli.d.ts +32 -0
  68. package/dist/search/grep-cli.d.ts.map +1 -0
  69. package/dist/search/grep-cli.js +101 -0
  70. package/dist/search/grep-cli.js.map +1 -0
  71. package/dist/search/grep.d.ts +55 -0
  72. package/dist/search/grep.d.ts.map +1 -0
  73. package/dist/search/grep.js +126 -0
  74. package/dist/search/grep.js.map +1 -0
  75. package/package.json +1 -1
@@ -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":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAwDvD,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,YAAY,GAAG,GAAG,CAAC;AACzB,MAAM,OAAO,GAAG,iBAAiB,CAAC;AAElC,SAAS,YAAY,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACpD,CAAC;AAQD;uEACuE;AACvE,SAAS,SAAS,CAAC,KAAc,EAAE,IAAY;IAC7C,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;YAAE,SAAS;QACnD,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;4EAG4E;AAC5E,SAAS,eAAe,CAAC,OAAqB,EAAE,IAAY;IAC1D,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI;YAAE,MAAM;QAC1B,IAAI,IAAI,IAAI,CAAC,CAAC,GAAG;YAAE,KAAK,GAAG,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;wEACwE;AACxE,SAAS,eAAe,CAAC,KAAc;IACrC,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,SAAS;QAC9C,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AACjH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,QAAgB,EAAE,OAAe,EAAE,OAAoB,EAAE;IACjG,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;IACjD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAE7D,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAEzG,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,cAAc,GAAG,CAAC,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACzD,CAAC;QAAC,MAAM,CAAC;YACP,cAAc,EAAE,CAAC;YACjB,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC;gBAAE,SAAS;YAE/B,IAAI,SAAS,IAAI,OAAO,EAAE,CAAC;gBACzB,aAAa,EAAE,CAAC;gBAChB,SAAS;YACX,CAAC;YACD,SAAS,EAAE,CAAC;YAEZ,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;YACrB,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;YAC/C,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,KAAK,GAAG;oBACN,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;oBACrC,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC/C,IAAI,EAAE,EAAE;iBACT,CAAC;gBACF,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;YACzB,CAAC;YACD,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACpH,CAAC;IACH,CAAC;IAED,MAAM,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAElH,OAAO;QACL,OAAO;QACP,aAAa,EAAE,SAAS,CAAC,MAAM;QAC/B,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,YAAY;QACpB,SAAS,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE;KAC1D,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nanonets/graft",
3
- "version": "0.4.5",
3
+ "version": "0.5.0",
4
4
  "description": "Build a repo's context graph as a folder of linked markdown files that live in the repo and stay in sync with the code through git.",
5
5
  "keywords": [
6
6
  "ai",