@nanonets/graft 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -52
- package/dist/ai/llm/types.d.ts +2 -2
- package/dist/ai/llm/types.js +1 -1
- package/dist/ask/ask.d.ts +49 -1
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +270 -68
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/fuse.d.ts +59 -17
- package/dist/ask/fuse.d.ts.map +1 -1
- package/dist/ask/fuse.js +51 -25
- package/dist/ask/fuse.js.map +1 -1
- package/dist/ask/graphrank.d.ts +6 -0
- package/dist/ask/graphrank.d.ts.map +1 -1
- package/dist/ask/graphrank.js +5 -1
- package/dist/ask/graphrank.js.map +1 -1
- package/dist/claude/format.d.ts +0 -1
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +18 -21
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hooks.d.ts +16 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +79 -2
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/settings-merge.d.ts.map +1 -1
- package/dist/claude/settings-merge.js +13 -6
- package/dist/claude/settings-merge.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +117 -76
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/cli-epilogue.js +1 -1
- package/dist/cli-epilogue.js.map +1 -1
- package/dist/cli.d.ts +3 -15
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +79 -45
- package/dist/cli.js.map +1 -1
- package/dist/context/node-file.d.ts +10 -0
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +34 -1
- package/dist/context/node-file.js.map +1 -1
- package/dist/context/savings.d.ts +6 -0
- package/dist/context/savings.d.ts.map +1 -1
- package/dist/context/savings.js +9 -1
- package/dist/context/savings.js.map +1 -1
- package/dist/engine.d.ts +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +7 -1
- package/dist/engine.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +37 -1
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/map.d.ts +34 -2
- package/dist/graph/map.d.ts.map +1 -1
- package/dist/graph/map.js +107 -23
- package/dist/graph/map.js.map +1 -1
- package/dist/graph/types.d.ts +12 -0
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/graph/workspace-cli.d.ts +37 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -0
- package/dist/graph/workspace-cli.js +74 -0
- package/dist/graph/workspace-cli.js.map +1 -0
- package/dist/graph/workspace.d.ts +116 -124
- package/dist/graph/workspace.d.ts.map +1 -1
- package/dist/graph/workspace.js +353 -297
- package/dist/graph/workspace.js.map +1 -1
- package/dist/hosts/instructions.d.ts.map +1 -1
- package/dist/hosts/instructions.js +3 -0
- package/dist/hosts/instructions.js.map +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +61 -1
- package/dist/mcp/tools.js.map +1 -1
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<!-- <img src="assets/graft.png" alt="Graft" width="220"/> -->
|
|
5
|
-
|
|
6
|
-
# Graft
|
|
3
|
+
<img src="assets/graft-hero.png" alt="Graft — open-source context layer for large codebases" width="100%"/>
|
|
7
4
|
|
|
8
5
|
**Your coding agent reads 30 files to change 3.**
|
|
9
6
|
**Graft gives it the map it should have read first.**
|
|
@@ -17,8 +14,18 @@
|
|
|
17
14
|
<img src="https://img.shields.io/badge/telemetry-none-546FFF?style=for-the-badge" />
|
|
18
15
|
</p>
|
|
19
16
|
|
|
20
|
-
<!-- numbers from
|
|
21
|
-
|
|
17
|
+
<!-- numbers from a 162-run benchmark (2026-07-22, 2 repos, 3 arms) — see Benchmark below -->
|
|
18
|
+
|
|
19
|
+
**vs. a standard coding session, no Graft at all:**
|
|
20
|
+
|
|
21
|
+
| Metric | With Graft |
|
|
22
|
+
|---|---|
|
|
23
|
+
| Cost | **32% less** |
|
|
24
|
+
| Tool calls | **46% fewer** |
|
|
25
|
+
| Latency | **60% lower** |
|
|
26
|
+
| Correctness | equal |
|
|
27
|
+
|
|
28
|
+
Same agent, same file tools, only the context differs. Pull the graph through the MCP tools instead of pushing it up front and correctness climbs **+5 points over cold** — the strongest result in the sweep. Full method → [Benchmark](#benchmark).
|
|
22
29
|
|
|
23
30
|
</div>
|
|
24
31
|
|
|
@@ -28,6 +35,25 @@
|
|
|
28
35
|
|
|
29
36
|
---
|
|
30
37
|
|
|
38
|
+
## Contents
|
|
39
|
+
|
|
40
|
+
- [Quick start](#quick-start)
|
|
41
|
+
- [Agent integration](#agent-integration) — [MCP server](#mcp-server) · [Claude Code (deep integration)](#claude-code-deep-integration)
|
|
42
|
+
- [The problem](#the-problem)
|
|
43
|
+
- [What Graft does](#what-graft-does)
|
|
44
|
+
- [How the graph gets built](#how-the-graph-gets-built)
|
|
45
|
+
- [What's in a node](#whats-in-a-node)
|
|
46
|
+
- [What runs where](#what-runs-where)
|
|
47
|
+
- [CLI](#cli)
|
|
48
|
+
- [Search & orient](#search--orient-graft-grep--graft-map) (`graft grep` / `graft map`)
|
|
49
|
+
- [Monorepos & multi-repo folders](#monorepos--multi-repo-folders)
|
|
50
|
+
- [Visualize it](#visualize-it-graft-viz) (`graft viz`)
|
|
51
|
+
- [Benchmark](#benchmark)
|
|
52
|
+
- [Development](#development)
|
|
53
|
+
- [License](#license)
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
31
57
|
## Quick start
|
|
32
58
|
|
|
33
59
|
```bash
|
|
@@ -37,10 +63,10 @@ graft init # build the graph + wire it into Claude Code
|
|
|
37
63
|
|
|
38
64
|
That is the whole setup. `graft init` builds `graft/` from your code and drops a statusline and hooks into `.claude/`, so from the next session on Graft rides along in Claude Code: it pulls the matching nodes into each prompt and rebuilds the graph in the background after every turn. No daemon, no re-indexing to remember, nothing to run or maintain by default — the graph is just files.
|
|
39
65
|
|
|
40
|
-
|
|
66
|
+
`graft build` adds `graft/` to your `.gitignore` automatically — the graph is a local, regenerable cache (like `node_modules`), not something you commit. What you share is the wiring `init` dropped into `.claude/`; each teammate runs `graft build` to generate their own graph:
|
|
41
67
|
|
|
42
68
|
```bash
|
|
43
|
-
git add
|
|
69
|
+
git add .claude && git commit -m "wire in graft"
|
|
44
70
|
```
|
|
45
71
|
|
|
46
72
|
Prefer not to install globally? `npx @nanonets/graft init` works the same way.
|
|
@@ -70,12 +96,18 @@ npx @nanonets/graft init
|
|
|
70
96
|
|
|
71
97
|
### MCP server
|
|
72
98
|
|
|
73
|
-
`graft init` also registers Graft's MCP server with agents that support it, so
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
`
|
|
99
|
+
`graft init` also registers Graft's MCP server with agents that support it, so these six tools appear natively, no shell required. Claude Code gets this too: `graft init` writes the server into the project's `.mcp.json` (restart Claude Code to load it). Skip with `--no-mcp`; run it manually with `graft mcp [dir]`.
|
|
100
|
+
|
|
101
|
+
| Tool | Takes | What it's for |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| `graft_ask` | a question | Ranked nodes with file:line, source inlined — usually the full answer, no follow-up read needed. |
|
|
104
|
+
| `graft_skeleton` | a file path | Every signature in that file, no bodies — the API surface for a tenth of the tokens. |
|
|
105
|
+
| `graft_callers` | a symbol | Who depends on it, or what it depends on with `direction: out`, N levels deep for blast radius. |
|
|
106
|
+
| `graft_grep` | a regex | Every hit, grouped by enclosing symbol, ranked by how coupled that symbol is. |
|
|
107
|
+
| `graft_map` | nothing | A first look at an unfamiliar repo: directory clusters, hubs, hotspots. |
|
|
108
|
+
| `graft_check` | nothing | Whether the local graph has drifted from the code. |
|
|
109
|
+
|
|
110
|
+
Register it by hand if your agent needs it explicit:
|
|
79
111
|
|
|
80
112
|
```json
|
|
81
113
|
{ "mcpServers": { "graft": { "command": "npx", "args": ["-y", "@nanonets/graft", "mcp"] } } }
|
|
@@ -126,7 +158,16 @@ Graft builds the graph in two passes, both powered by a language model:
|
|
|
126
158
|
1. **Read each file.** Every source file is summarized once into a short description of what it does.
|
|
127
159
|
2. **Group into nodes.** Those summaries are grouped into a curated set of nodes (subsystems, key files, and concepts) with typed links between them. Graft chooses the right level of detail for you instead of making one node per file, so a big repo becomes a few dozen readable nodes.
|
|
128
160
|
|
|
129
|
-
|
|
161
|
+
```mermaid
|
|
162
|
+
flowchart LR
|
|
163
|
+
S[Source files] --> T["Tier 1 — tree-sitter<br/>no model, no key"]
|
|
164
|
+
S --> P1["Pass 1 — LLM summarizes<br/>each file (--deep)"]
|
|
165
|
+
T --> W["graft/.graph/wiring.json<br/>per-symbol code graph"]
|
|
166
|
+
P1 --> P2["Pass 2 — group into nodes<br/>+ typed links"]
|
|
167
|
+
P2 --> N["graft/*.md<br/>markdown node graph"]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Both LLM passes are cached by content hash. Re-running only touches the files that changed, so the second build is fast and cheap.
|
|
130
171
|
|
|
131
172
|
Alongside the markdown graph, `graft build` builds `graft/.graph/wiring.json` — a per-symbol code graph — plus a per-file wiring card mirroring your source tree. Tier 1 is pure tree-sitter (every function, class, and call edge; deterministic, no model, no network), which is why plain `graft build` needs no key. The `--deep` pass adds a one-line summary and a crux excerpt per symbol, cached by body hash.
|
|
132
173
|
|
|
@@ -154,22 +195,6 @@ _Summary, sources, links, and notes ship today in markdown nodes. The crux ships
|
|
|
154
195
|
|
|
155
196
|
---
|
|
156
197
|
|
|
157
|
-
## Keeping it honest (CI)
|
|
158
|
-
|
|
159
|
-
A graph that has drifted from the code is worse than no graph. `graft check` compares each node's tracked source hashes against the current files and fails if the graph is stale. Drop it in CI so a pull request cannot merge with an out-of-date map.
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
graft check # exits non-zero if graft/ has drifted
|
|
163
|
-
graft check --json # machine-readable drift report
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
When the wiring graph exists, `graft check` validates it too — structural drift (symbols added, removed, or changed since the last `graft build`) and stale summaries both fail the check. A repo without a wiring graph is not penalized; the markdown graph stands alone.
|
|
167
|
-
|
|
168
|
-
<!-- placeholder: planned, not yet in the CLI -->
|
|
169
|
-
> **Planned: auto-regen on PR.** A single CI bot will regenerate changed nodes on a pull request and push the update, so the graph stays current without anyone remembering to run `build`. Until then, regenerate with `graft build --deep` and commit it alongside your code.
|
|
170
|
-
|
|
171
|
-
---
|
|
172
|
-
|
|
173
198
|
## What runs where
|
|
174
199
|
|
|
175
200
|
- **On your machine, no key, no network:** the structural code graph. `graft build` (wiring graph + per-file cards), `graft check`, and `graft ask` are deterministic tree-sitter — they never call a model.
|
|
@@ -189,6 +214,9 @@ graft build --extensions .ts .py # only include these code extensions
|
|
|
189
214
|
|
|
190
215
|
graft ask "<task>" [dir] # query the graph — ranked nodes + exact file:line (no LLM, no key)
|
|
191
216
|
graft ask "<task>" --json # machine-readable result
|
|
217
|
+
graft ask "<task>" --in <scope> # narrow to one sub-project of a monorepo/multi-repo folder (see below)
|
|
218
|
+
|
|
219
|
+
graft skeleton <file> [dir] # every signature in one file, no bodies — the API surface for ~1/10th the tokens (no LLM, no key)
|
|
192
220
|
|
|
193
221
|
graft callers <symbol> [dir] # who calls/references/imports/implements/extends a symbol (no LLM, no key)
|
|
194
222
|
graft callers <symbol> --direction out # the reverse: what the symbol itself calls/references (was `graft callees`)
|
|
@@ -248,17 +276,35 @@ with file/symbol counts, each dir's local hubs, and the global hotspots —
|
|
|
248
276
|
all ranked by in-degree, no LLM, no key:
|
|
249
277
|
|
|
250
278
|
```
|
|
251
|
-
repo map —
|
|
279
|
+
repo map — 113 files · 687 symbols · 2186 edges · typescript
|
|
252
280
|
|
|
253
|
-
src/
|
|
254
|
-
test/
|
|
281
|
+
src/ 63 files · 527 symbols hubs: contextDirFor (node-file.ts, 21←), wiringPath (write.ts, 14←), buildGraph (build.ts, 11←)
|
|
282
|
+
test/ 43 files · 102 symbols hubs: edge (graph-traverse.test.ts, 4←), graphOf (graph-traverse.test.ts, 4←), fileNode (graph-map.test.ts, 3←)
|
|
255
283
|
viewer/ 5 files · 58 symbols hubs: $ (main.ts, 9←), activeGraph (main.ts, 5←), cvar (data.ts, 5←)
|
|
256
|
-
bench/ 8 files · 42 symbols hubs: makeClient (llm.ts, 3←), buildMarkdown (report.ts, 2←), judge (judge.ts, 2←)
|
|
257
284
|
scripts/ 2 files · 0 symbols
|
|
258
285
|
|
|
259
|
-
hotspots:
|
|
286
|
+
hotspots: contextDirFor · function · src/context/node-file.ts:L100-L103 · 21← wiringPath · function · src/graph/write.ts:L20-L22 · 14← buildGraph · function · src/graph/build.ts:L104-L218 · 11← ...
|
|
260
287
|
```
|
|
261
288
|
|
|
289
|
+
## Monorepos & multi-repo folders
|
|
290
|
+
|
|
291
|
+
Graft handles two shapes without any config:
|
|
292
|
+
|
|
293
|
+
- **A monorepo with one `.git`** (a `pnpm-workspace.yaml`/`package.json`
|
|
294
|
+
`workspaces`, or per-package `go.mod`/`pyproject.toml`/`Cargo.toml`) —
|
|
295
|
+
`graft build` discovers each sub-project as a ranking scope. `ask`/`map`
|
|
296
|
+
rank every scope on its own terms and fuse the results, so the biggest
|
|
297
|
+
sub-project can't drown a small one; hits carry `[scope/]` labels, and
|
|
298
|
+
`graft map` groups its directory clusters by scope first.
|
|
299
|
+
- **A folder of separate git repos** (no `.git` at the top) — `graft build`
|
|
300
|
+
auto-splits: each child gets its own (git-ignored) `graft/`, and the parent
|
|
301
|
+
gets a `graft/workspace.json` index. Queries from the parent federate across
|
|
302
|
+
every child, always labeled `<child>/`. Run `graft build` inside a child to
|
|
303
|
+
work on just that repo.
|
|
304
|
+
|
|
305
|
+
Either way, narrow to one sub-project with `graft ask "<task>" --in <scope>/`
|
|
306
|
+
once you know where you're working.
|
|
307
|
+
|
|
262
308
|
## Visualize it (`graft viz`)
|
|
263
309
|
|
|
264
310
|
`graft viz` opens a local, interactive view of both graphs — no install, no dev
|
|
@@ -292,26 +338,21 @@ normalized on load — no regeneration needed.
|
|
|
292
338
|
|
|
293
339
|
## Benchmark
|
|
294
340
|
|
|
295
|
-
|
|
341
|
+
An agent that reads the graph should be cheaper and faster without getting more answers wrong. That's the whole claim, so we measured it instead of asserting it.
|
|
296
342
|
|
|
297
|
-
|
|
343
|
+
The harness ran three variants of the same Claude Sonnet 5 agent with the same file tools: **cold** (explores from zero), **Graft** (a `graft ask --source` bundle pushed up front), and **pull** (graft_ask/graft_skeleton tools, nothing injected — context paid for only when asked). An Opus 4.8 judge scored correctness with a required-keyword floor, so a fast-but-wrong answer couldn't win by being fast. Cost is cache-aware: reads ≈0.1×, writes 1.25×, the billing model agents actually run under.
|
|
298
344
|
|
|
299
|
-
|
|
300
|
-
|---|---|---|---|
|
|
301
|
-
| Cost ($) | 0.0429 | **0.0292 (−32%)** | 0.0362 (−16%) |
|
|
302
|
-
| Uncached input tokens | 8,070 | **4,650 (−42%)** | 5,965 (−26%) |
|
|
303
|
-
| Tool calls | 4.2 | **2.3 (−46%)** | 4.2 (−1%) |
|
|
304
|
-
| Latency (s) | 39.8 | **15.8 (−60%)** | 39.5 (−1%) |
|
|
305
|
-
| Correctness | 93% | 93% | **98% (+5 pts)** |
|
|
345
|
+
162 runs, two repos (graft itself and a real Node/Express auth service), 3 trials each, tasks split between single-file and multi-file questions.
|
|
306
346
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
347
|
+
| Metric (mean/task) | Cold | Graft |
|
|
348
|
+
|---|---|---|
|
|
349
|
+
| Cost ($) | 0.0429 | **0.0292 (−32%)** |
|
|
350
|
+
| Uncached input tokens | 8,070 | **4,650 (−42%)** |
|
|
351
|
+
| Tool calls | 4.2 | **2.3 (−46%)** |
|
|
352
|
+
| Latency (s) | 39.8 | **15.8 (−60%)** |
|
|
353
|
+
| Correctness | 93% | 93% (equal) |
|
|
313
354
|
|
|
314
|
-
|
|
355
|
+
Graft never answered worse than cold, on any corpus. The pull variant gave up most of that speed for something bigger: correctness jumped to 98%, +5 points over cold, the strongest single result in the sweep. Push when speed is what you need; pull when being right matters more.
|
|
315
356
|
|
|
316
357
|
---
|
|
317
358
|
|
package/dist/ai/llm/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Provider-neutral chat transport.
|
|
3
3
|
*
|
|
4
4
|
* Every LLM call in graft — the engine's single-shot summarize/synthesize/crux
|
|
5
|
-
* ops
|
|
5
|
+
* ops, and any multi-turn tool-use loop built on top — goes through one interface,
|
|
6
6
|
* {@link ChatModel}. Adapters translate this neutral shape to a concrete SDK
|
|
7
7
|
* (OpenAI-compatible or native Anthropic). Nothing above this layer knows which
|
|
8
8
|
* provider is in play, so adding a provider is a new adapter, never a change to
|
|
@@ -37,7 +37,7 @@ export interface Message {
|
|
|
37
37
|
/**
|
|
38
38
|
* Request a provider cache marker (`cache_control: ephemeral`) on THIS message.
|
|
39
39
|
* The transport only understands this per-message flag; any sliding/rotation
|
|
40
|
-
* policy lives in the caller
|
|
40
|
+
* policy lives in the caller.
|
|
41
41
|
*/
|
|
42
42
|
cacheBreakpoint?: boolean;
|
|
43
43
|
/**
|
package/dist/ai/llm/types.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Provider-neutral chat transport.
|
|
3
3
|
*
|
|
4
4
|
* Every LLM call in graft — the engine's single-shot summarize/synthesize/crux
|
|
5
|
-
* ops
|
|
5
|
+
* ops, and any multi-turn tool-use loop built on top — goes through one interface,
|
|
6
6
|
* {@link ChatModel}. Adapters translate this neutral shape to a concrete SDK
|
|
7
7
|
* (OpenAI-compatible or native Anthropic). Nothing above this layer knows which
|
|
8
8
|
* provider is in play, so adding a provider is a new adapter, never a change to
|
package/dist/ask/ask.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Savings } from "../context/savings.js";
|
|
2
|
-
import type { Relation } from "../graph/types.js";
|
|
2
|
+
import type { NodeV1, Relation } from "../graph/types.js";
|
|
3
3
|
export interface AskHit {
|
|
4
4
|
kind: "concept" | "symbol" | "caller" | "callee";
|
|
5
5
|
title: string;
|
|
@@ -13,6 +13,10 @@ export interface AskHit {
|
|
|
13
13
|
* This is what makes `ask` substitutive — the agent reads the span here
|
|
14
14
|
* instead of opening the file, so no source read happens on top of the query. */
|
|
15
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;
|
|
16
20
|
}
|
|
17
21
|
export interface AskResult {
|
|
18
22
|
query: string;
|
|
@@ -34,7 +38,45 @@ export interface AskResult {
|
|
|
34
38
|
* best result, i.e. the pack is probably noise for this prompt. Absent in
|
|
35
39
|
* structural mode — a resolved "who calls X" is itself the relevance signal. */
|
|
36
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
|
+
};
|
|
37
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;
|
|
38
80
|
export interface AskOptions {
|
|
39
81
|
contextDir?: string;
|
|
40
82
|
limit?: number;
|
|
@@ -51,6 +93,12 @@ export interface AskOptions {
|
|
|
51
93
|
* decision point, ~10× cheaper than the full span — and the pack marks each
|
|
52
94
|
* crux so the agent knows `--full` (or the file itself) has the rest. */
|
|
53
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;
|
|
54
102
|
}
|
|
55
103
|
/** Answer a query from the graft/ graph at `dir`. Deterministic, $0. */
|
|
56
104
|
export declare function ask(dir: string, query: string, opts?: AskOptions): AskResult;
|
package/dist/ask/ask.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/ask/ask.ts"],"names":[],"mappings":"AAmBA,OAAO,
|
|
1
|
+
{"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../src/ask/ask.ts"],"names":[],"mappings":"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"}
|