@nanonets/graft 0.5.1 → 0.7.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 (85) hide show
  1. package/README.md +29 -7
  2. package/dist/ask/ask.d.ts +52 -1
  3. package/dist/ask/ask.d.ts.map +1 -1
  4. package/dist/ask/ask.js +274 -83
  5. package/dist/ask/ask.js.map +1 -1
  6. package/dist/ask/fuse.d.ts +59 -17
  7. package/dist/ask/fuse.d.ts.map +1 -1
  8. package/dist/ask/fuse.js +51 -25
  9. package/dist/ask/fuse.js.map +1 -1
  10. package/dist/ask/graphrank.d.ts +6 -0
  11. package/dist/ask/graphrank.d.ts.map +1 -1
  12. package/dist/ask/graphrank.js +5 -1
  13. package/dist/ask/graphrank.js.map +1 -1
  14. package/dist/claude/format.js +1 -1
  15. package/dist/claude/format.js.map +1 -1
  16. package/dist/claude/hooks.d.ts +16 -0
  17. package/dist/claude/hooks.d.ts.map +1 -1
  18. package/dist/claude/hooks.js +57 -2
  19. package/dist/claude/hooks.js.map +1 -1
  20. package/dist/claude/init.d.ts +3 -0
  21. package/dist/claude/init.d.ts.map +1 -1
  22. package/dist/claude/init.js +6 -1
  23. package/dist/claude/init.js.map +1 -1
  24. package/dist/claude/skill-template.d.ts.map +1 -1
  25. package/dist/claude/skill-template.js +20 -9
  26. package/dist/claude/skill-template.js.map +1 -1
  27. package/dist/cli.d.ts +3 -14
  28. package/dist/cli.d.ts.map +1 -1
  29. package/dist/cli.js +99 -70
  30. package/dist/cli.js.map +1 -1
  31. package/dist/context/savings.d.ts +34 -0
  32. package/dist/context/savings.d.ts.map +1 -0
  33. package/dist/context/savings.js +49 -0
  34. package/dist/context/savings.js.map +1 -0
  35. package/dist/engine.d.ts +1 -0
  36. package/dist/engine.d.ts.map +1 -1
  37. package/dist/engine.js +7 -1
  38. package/dist/engine.js.map +1 -1
  39. package/dist/graph/build.d.ts.map +1 -1
  40. package/dist/graph/build.js +33 -0
  41. package/dist/graph/build.js.map +1 -1
  42. package/dist/graph/map.d.ts +38 -2
  43. package/dist/graph/map.d.ts.map +1 -1
  44. package/dist/graph/map.js +111 -24
  45. package/dist/graph/map.js.map +1 -1
  46. package/dist/graph/scopes.d.ts +15 -0
  47. package/dist/graph/scopes.d.ts.map +1 -1
  48. package/dist/graph/scopes.js +23 -0
  49. package/dist/graph/scopes.js.map +1 -1
  50. package/dist/graph/traverse-cli.d.ts +28 -18
  51. package/dist/graph/traverse-cli.d.ts.map +1 -1
  52. package/dist/graph/traverse-cli.js +68 -43
  53. package/dist/graph/traverse-cli.js.map +1 -1
  54. package/dist/graph/traverse.d.ts +35 -14
  55. package/dist/graph/traverse.d.ts.map +1 -1
  56. package/dist/graph/traverse.js +46 -20
  57. package/dist/graph/traverse.js.map +1 -1
  58. package/dist/graph/types.d.ts +12 -0
  59. package/dist/graph/types.d.ts.map +1 -1
  60. package/dist/graph/workspace-cli.d.ts +37 -0
  61. package/dist/graph/workspace-cli.d.ts.map +1 -0
  62. package/dist/graph/workspace-cli.js +70 -0
  63. package/dist/graph/workspace-cli.js.map +1 -0
  64. package/dist/graph/workspace.d.ts +128 -0
  65. package/dist/graph/workspace.d.ts.map +1 -0
  66. package/dist/graph/workspace.js +395 -0
  67. package/dist/graph/workspace.js.map +1 -0
  68. package/dist/hosts/instructions.d.ts.map +1 -1
  69. package/dist/hosts/instructions.js +7 -3
  70. package/dist/hosts/instructions.js.map +1 -1
  71. package/dist/hosts/mcp-config.d.ts +5 -0
  72. package/dist/hosts/mcp-config.d.ts.map +1 -1
  73. package/dist/hosts/mcp-config.js +2 -2
  74. package/dist/hosts/mcp-config.js.map +1 -1
  75. package/dist/mcp/tools.d.ts.map +1 -1
  76. package/dist/mcp/tools.js +94 -66
  77. package/dist/mcp/tools.js.map +1 -1
  78. package/dist/search/grep-cli.d.ts.map +1 -1
  79. package/dist/search/grep-cli.js +4 -0
  80. package/dist/search/grep-cli.js.map +1 -1
  81. package/dist/search/grep.d.ts +4 -0
  82. package/dist/search/grep.d.ts.map +1 -1
  83. package/dist/search/grep.js +2 -0
  84. package/dist/search/grep.js.map +1 -1
  85. package/package.json +1 -1
package/README.md CHANGED
@@ -71,9 +71,11 @@ npx @nanonets/graft init
71
71
  ### MCP server
72
72
 
73
73
  `graft init` also registers Graft's MCP server with agents that support it, so
74
- `graft_ask`, `graft_check`, and `graft_blast_radius` appear as native tools —
75
- no shell required. Skip with `--no-mcp`. Run it manually with `graft mcp [dir]`,
76
- or register it by hand:
74
+ `graft_ask`, `graft_callers`, `graft_grep`, `graft_skeleton`, `graft_map`, and
75
+ `graft_check` appear as native tools — no shell required. Claude Code now gets
76
+ this too: `graft init` writes the server into the project's `.mcp.json` (restart
77
+ Claude Code to load it). Skip with `--no-mcp`. Run it manually with
78
+ `graft mcp [dir]`, or register it by hand:
77
79
 
78
80
  ```json
79
81
  { "mcpServers": { "graft": { "command": "npx", "args": ["-y", "@nanonets/graft", "mcp"] } } }
@@ -187,10 +189,11 @@ graft build --extensions .ts .py # only include these code extensions
187
189
 
188
190
  graft ask "<task>" [dir] # query the graph — ranked nodes + exact file:line (no LLM, no key)
189
191
  graft ask "<task>" --json # machine-readable result
192
+ graft ask "<task>" --in <scope> # narrow to one sub-project of a monorepo/multi-repo folder (see below)
190
193
 
191
194
  graft callers <symbol> [dir] # who calls/references/imports/implements/extends a symbol (no LLM, no key)
192
- graft callees <symbol> [dir] # what a symbol calls/references/imports/implements/extends (no LLM, no key)
193
- graft impact <symbol> [dir] -d N # BFS over incoming edges — who breaks if this symbol changes (no LLM, no key)
195
+ graft callers <symbol> --direction out # the reverse: what the symbol itself calls/references (was `graft callees`)
196
+ graft callers <symbol> -d N # walk transitively out to depth N — full blast radius (was `graft impact`)
194
197
 
195
198
  graft grep "<regex>" [dir] # exhaustive regex search over indexed files, grouped by enclosing symbol (no LLM, no key)
196
199
  graft grep "<regex>" --in <path> # narrow to files whose path contains this substring
@@ -205,7 +208,7 @@ graft check --json # print the drift report as JSON
205
208
  graft viz [dir] # see the graph: serves an interactive viewer on localhost
206
209
  graft viz --port 5000 --no-open # pick a port; don't auto-open the browser
207
210
 
208
- graft init [dir] # wire Graft into the coding agents detected in this repo (Claude Code always gets full hooks + statusline)
211
+ graft init [dir] # wire Graft into the coding agents detected in this repo (Claude Code always gets full hooks + statusline + MCP)
209
212
  graft init --no-build # wire the files only; don't build the graph
210
213
  graft init --agents cursor kiro # wire only these agents (ids: agents, cursor, gemini, copilot, kiro, windsurf, claude)
211
214
  graft init --all-agents # wire every known agent, detected or not
@@ -221,7 +224,7 @@ graft --version, -v # print the installed version and exit
221
224
 
222
225
  Method calls resolve through the receiver's type — constructor assignments
223
226
  (`self.router = APIRouter()`) and type annotations, not just the call-site
224
- name — so `callers`/`impact`/`grep --in` return calls bound to the right
227
+ name — so `callers`/`grep --in` return calls bound to the right
225
228
  type on method-heavy code, not every method anywhere with that name.
226
229
 
227
230
  ## Search & orient (`graft grep` / `graft map`)
@@ -257,6 +260,25 @@ scripts/ 2 files · 0 symbols
257
260
  hotspots: set · method · src/graph/bindings.ts:L21-L23 · 38← contextDirFor · function · src/context/node-file.ts:L100-L103 · 11← wiringPath · function · src/graph/write.ts:L20-L22 · 10← ...
258
261
  ```
259
262
 
263
+ ## Monorepos & multi-repo folders
264
+
265
+ Graft handles two shapes without any config:
266
+
267
+ - **A monorepo with one `.git`** (a `pnpm-workspace.yaml`/`package.json`
268
+ `workspaces`, or per-package `go.mod`/`pyproject.toml`/`Cargo.toml`) —
269
+ `graft build` discovers each sub-project as a ranking scope. `ask`/`map`
270
+ rank every scope on its own terms and fuse the results, so the biggest
271
+ sub-project can't drown a small one; hits carry `[scope/]` labels, and
272
+ `graft map` groups its directory clusters by scope first.
273
+ - **A folder of separate git repos** (no `.git` at the top) — `graft build`
274
+ auto-splits: each child keeps its own committable `graft/`, and the parent
275
+ gets a `graft/workspace.json` index. Queries from the parent federate across
276
+ every child, always labeled `<child>/`. Run `graft build` inside a child to
277
+ work on just that repo.
278
+
279
+ Either way, narrow to one sub-project with `graft ask "<task>" --in <scope>/`
280
+ once you know where you're working.
281
+
260
282
  ## Visualize it (`graft viz`)
261
283
 
262
284
  `graft viz` opens a local, interactive view of both graphs — no install, no dev
package/dist/ask/ask.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import type { Relation } from "../graph/types.js";
1
+ import { type Savings } from "../context/savings.js";
2
+ import type { NodeV1, Relation } from "../graph/types.js";
2
3
  export interface AskHit {
3
4
  kind: "concept" | "symbol" | "caller" | "callee";
4
5
  title: string;
@@ -12,6 +13,10 @@ export interface AskHit {
12
13
  * This is what makes `ask` substitutive — the agent reads the span here
13
14
  * instead of opening the file, so no source read happens on top of the query. */
14
15
  code?: string;
16
+ /** Multi-scope repos only: the ranking scope (path prefix, "" = root) this
17
+ * hit was ranked within — answers "which sub-project is this from?". Drives
18
+ * the `[scope/] ` label in formatAsk. Absent on single-scope repos. */
19
+ scope?: string;
15
20
  }
16
21
  export interface AskResult {
17
22
  query: string;
@@ -33,7 +38,45 @@ export interface AskResult {
33
38
  * best result, i.e. the pack is probably noise for this prompt. Absent in
34
39
  * structural mode — a resolved "who calls X" is itself the relevance signal. */
35
40
  coverage?: number;
41
+ /** Like {@link coverage}, but the top hit's idf-weighted matched share over
42
+ * its NAME + PATH fields ONLY (body excluded) — a match-STRENGTH signal:
43
+ * "did the query hit a high-value field, or only incidental body tokens?".
44
+ * A body-only collision (a variable that happens to share a query word) has
45
+ * `coverageStrong === 0` while `coverage` can still look respectable. Used by
46
+ * workspace federation to gate a weak child out of the cross-repo ranking.
47
+ * Absent in structural mode; same lexical-only contract as `coverage`. */
48
+ coverageStrong?: number;
49
+ /** Multi-scope lexical results only: which scopes federated into the fused
50
+ * ranking, plus scopes that matched too weakly to federate (with their best
51
+ * doc id). Drives formatAsk's `matched in:` / `also matched:` footer.
52
+ * Absent on single-scope repos — zero output change there. */
53
+ scopes?: {
54
+ federated: string[];
55
+ alsoMatched: {
56
+ scope: string;
57
+ bestId: string;
58
+ }[];
59
+ };
36
60
  }
61
+ /** Idf-weighted share (0..1) of the query a document matches: each query term
62
+ * counts by its rarity, so this separates task prompts from chatter in a way a
63
+ * raw term count can't. A conversational prompt's words are either off-corpus
64
+ * (rare → heavy, unmatched → sinks the ratio) or generic code words ("list",
65
+ * "write": common → near-weightless even when they collide with a symbol name);
66
+ * a task prompt matches exactly its rare, discriminating identifiers. Terms the
67
+ * corpus has never seen take `dfltIdf` (the df=0 weight). */
68
+ /** The match-STRENGTH share behind `coverageStrong`: idf-weighted share of the
69
+ * query matched in the node's NAME field ONLY. The PATH field is deliberately
70
+ * excluded — a coincidental generic directory (`gateway/`) or file basename
71
+ * (`gateway.ts`) in an unrelated repo would otherwise clear the strength gate
72
+ * and float that repo to the top; an on-topic path-organized repo is still
73
+ * rescued by the broad-coverage HIGH_FLOOR clause instead. For the same reason
74
+ * a `kind:"file"` node contributes zero strength: its `name` is a basename (a
75
+ * path component), not a symbol name, so a file whose basename happens to share
76
+ * a query word is not a strong match. */
77
+ export declare function strongShare(q: Map<string, number>, node: NodeV1, doc: {
78
+ name: Map<string, number>;
79
+ }, idf: Map<string, number>, dfltIdf: number): number;
37
80
  export interface AskOptions {
38
81
  contextDir?: string;
39
82
  limit?: number;
@@ -50,6 +93,12 @@ export interface AskOptions {
50
93
  * decision point, ~10× cheaper than the full span — and the pack marks each
51
94
  * crux so the agent knows `--full` (or the file itself) has the rest. */
52
95
  full?: boolean;
96
+ /** Narrow the doc/node set to this path prefix BEFORE scoring (segment-aware,
97
+ * like `scopeOf` — "frontend" never matches "frontend-utils"). Per-scope
98
+ * IDF/BM25/walk come free: the filtered set is usually one scope, so the
99
+ * existing multi-scope machinery degrades to its single-scope passthrough
100
+ * with no scope labels. A prefix matching nothing indexed throws. */
101
+ in?: string;
53
102
  }
54
103
  /** Answer a query from the graft/ graph at `dir`. Deterministic, $0. */
55
104
  export declare function ask(dir: string, query: string, opts?: AskOptions): AskResult;
@@ -65,6 +114,8 @@ export interface SkeletonResult {
65
114
  file: string;
66
115
  entries: SkeletonEntry[];
67
116
  note?: string;
117
+ /** Tokens-saved baseline: this file read whole vs the signatures-only view. */
118
+ saved?: Savings;
68
119
  }
69
120
  /** Signatures-only view of one file, straight from the wiring graph — the
70
121
  * cheapest way to understand a file's API surface (~10× less than reading it).
@@ -1 +1 @@
1
- {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/ask/ask.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAA2B,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAI3E,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd;;qFAEiF;IACjF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,GAAG,SAAS,GAAG,OAAO,CAAC;IACzC,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;sFAEkF;IAClF,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD;;;;oFAIgF;IAChF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA2aD,MAAM,WAAW,UAAU;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;qFACiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;;sFAEkF;IAClF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;6EAIyE;IACzE,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAsFD,wEAAwE;AACxE,wBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,GAAE,UAAe,GAAG,SAAS,CA8BhF;AAID,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;2EAE2E;AAC3E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,cAAc,CA6BtG;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,CAAC,EAAE,cAAc,GAAG,MAAM,CASxD;AAOD,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAsC9C"}
1
+ {"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/ask/ask.ts"],"names":[],"mappings":"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"}