@nanonets/graft 0.10.0 → 0.12.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 +34 -13
- package/dist/ai/crux.d.ts.map +1 -1
- package/dist/ai/crux.js +7 -6
- package/dist/ai/crux.js.map +1 -1
- package/dist/ai/failure.d.ts +49 -0
- package/dist/ai/failure.d.ts.map +1 -0
- package/dist/ai/failure.js +74 -0
- package/dist/ai/failure.js.map +1 -0
- package/dist/ai/llm/anthropic.d.ts.map +1 -1
- package/dist/ai/llm/anthropic.js +4 -1
- package/dist/ai/llm/anthropic.js.map +1 -1
- package/dist/ai/llm/claude-cli.d.ts +60 -0
- package/dist/ai/llm/claude-cli.d.ts.map +1 -0
- package/dist/ai/llm/claude-cli.js +417 -0
- package/dist/ai/llm/claude-cli.js.map +1 -0
- package/dist/ai/llm/openai.d.ts.map +1 -1
- package/dist/ai/llm/openai.js +2 -0
- package/dist/ai/llm/openai.js.map +1 -1
- package/dist/ai/llm/types.d.ts +9 -0
- package/dist/ai/llm/types.d.ts.map +1 -1
- package/dist/ai/llm/types.js +12 -1
- package/dist/ai/llm/types.js.map +1 -1
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +39 -45
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/fuse.d.ts +83 -46
- package/dist/ask/fuse.d.ts.map +1 -1
- package/dist/ask/fuse.js +165 -67
- package/dist/ask/fuse.js.map +1 -1
- package/dist/blast/blast-cli.d.ts +30 -0
- package/dist/blast/blast-cli.d.ts.map +1 -0
- package/dist/blast/blast-cli.js +163 -0
- package/dist/blast/blast-cli.js.map +1 -0
- package/dist/blast/blast.d.ts +119 -0
- package/dist/blast/blast.d.ts.map +1 -0
- package/dist/blast/blast.js +383 -0
- package/dist/blast/blast.js.map +1 -0
- package/dist/blast/diff.d.ts +53 -0
- package/dist/blast/diff.d.ts.map +1 -0
- package/dist/blast/diff.js +193 -0
- package/dist/blast/diff.js.map +1 -0
- package/dist/blast/modules.d.ts +33 -0
- package/dist/blast/modules.d.ts.map +1 -0
- package/dist/blast/modules.js +83 -0
- package/dist/blast/modules.js.map +1 -0
- package/dist/blast/name.d.ts +61 -0
- package/dist/blast/name.d.ts.map +1 -0
- package/dist/blast/name.js +233 -0
- package/dist/blast/name.js.map +1 -0
- package/dist/blast/render.d.ts +37 -0
- package/dist/blast/render.d.ts.map +1 -0
- package/dist/blast/render.js +300 -0
- package/dist/blast/render.js.map +1 -0
- package/dist/blast/viz.d.ts +17 -0
- package/dist/blast/viz.d.ts.map +1 -0
- package/dist/blast/viz.js +324 -0
- package/dist/blast/viz.js.map +1 -0
- package/dist/claude/hooks.d.ts +13 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +44 -4
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/shim-template.d.ts.map +1 -1
- package/dist/claude/shim-template.js +45 -15
- package/dist/claude/shim-template.js.map +1 -1
- package/dist/claude/state.d.ts +5 -0
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-picker.d.ts +44 -5
- package/dist/cli-picker.d.ts.map +1 -1
- package/dist/cli-picker.js +73 -26
- package/dist/cli-picker.js.map +1 -1
- package/dist/cli.js +270 -14
- package/dist/cli.js.map +1 -1
- package/dist/context/build.d.ts +8 -0
- package/dist/context/build.d.ts.map +1 -1
- package/dist/context/build.js +57 -9
- package/dist/context/build.js.map +1 -1
- package/dist/context/check.d.ts.map +1 -1
- package/dist/context/check.js +7 -6
- package/dist/context/check.js.map +1 -1
- package/dist/context/node-file.d.ts.map +1 -1
- package/dist/context/node-file.js +9 -2
- package/dist/context/node-file.js.map +1 -1
- package/dist/graph/bindings.d.ts.map +1 -1
- package/dist/graph/bindings.js +245 -2
- package/dist/graph/bindings.js.map +1 -1
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +36 -16
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/check.d.ts +4 -0
- package/dist/graph/check.d.ts.map +1 -1
- package/dist/graph/check.js +8 -1
- package/dist/graph/check.js.map +1 -1
- package/dist/graph/container.d.ts +63 -0
- package/dist/graph/container.d.ts.map +1 -0
- package/dist/graph/container.js +185 -0
- package/dist/graph/container.js.map +1 -0
- package/dist/graph/enrich.d.ts +18 -0
- package/dist/graph/enrich.d.ts.map +1 -1
- package/dist/graph/enrich.js +55 -2
- package/dist/graph/enrich.js.map +1 -1
- package/dist/graph/extract.d.ts +8 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +401 -12
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/generic.d.ts +34 -1
- package/dist/graph/generic.d.ts.map +1 -1
- package/dist/graph/generic.js +176 -6
- package/dist/graph/generic.js.map +1 -1
- package/dist/graph/invariants.d.ts +32 -0
- package/dist/graph/invariants.d.ts.map +1 -0
- package/dist/graph/invariants.js +49 -0
- package/dist/graph/invariants.js.map +1 -0
- package/dist/graph/queries/clojure.scm +58 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +249 -23
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/scopes.d.ts +2 -2
- package/dist/graph/scopes.d.ts.map +1 -1
- package/dist/graph/scopes.js +8 -6
- package/dist/graph/scopes.js.map +1 -1
- package/dist/graph/source-files.d.ts +13 -4
- package/dist/graph/source-files.d.ts.map +1 -1
- package/dist/graph/source-files.js +35 -12
- package/dist/graph/source-files.js.map +1 -1
- package/dist/graph/types.d.ts +3 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/graph/workspace-cli.d.ts +2 -0
- package/dist/graph/workspace-cli.d.ts.map +1 -1
- package/dist/graph/workspace-cli.js +10 -4
- package/dist/graph/workspace-cli.js.map +1 -1
- package/dist/graph/workspace.d.ts +11 -6
- package/dist/graph/workspace.d.ts.map +1 -1
- package/dist/graph/workspace.js +24 -13
- package/dist/graph/workspace.js.map +1 -1
- package/dist/graph/write.d.ts.map +1 -1
- package/dist/graph/write.js +25 -2
- package/dist/graph/write.js.map +1 -1
- package/dist/hosts/antigravity.d.ts +7 -0
- package/dist/hosts/antigravity.d.ts.map +1 -0
- package/dist/hosts/antigravity.js +42 -0
- package/dist/hosts/antigravity.js.map +1 -0
- package/dist/hosts/codex-hooks.d.ts +3 -3
- package/dist/hosts/codex-hooks.d.ts.map +1 -1
- package/dist/hosts/codex-hooks.js +27 -21
- package/dist/hosts/codex-hooks.js.map +1 -1
- package/dist/hosts/init.d.ts.map +1 -1
- package/dist/hosts/init.js +6 -1
- package/dist/hosts/init.js.map +1 -1
- package/dist/hosts/mcp-config.d.ts.map +1 -1
- package/dist/hosts/mcp-config.js +7 -0
- package/dist/hosts/mcp-config.js.map +1 -1
- package/dist/hosts/plan.d.ts +1 -1
- package/dist/hosts/plan.d.ts.map +1 -1
- package/dist/hosts/plan.js +2 -0
- package/dist/hosts/plan.js.map +1 -1
- package/dist/hosts/registry.d.ts.map +1 -1
- package/dist/hosts/registry.js +13 -0
- package/dist/hosts/registry.js.map +1 -1
- package/dist/ingest/fs.d.ts +9 -2
- package/dist/ingest/fs.d.ts.map +1 -1
- package/dist/ingest/fs.js +100 -16
- package/dist/ingest/fs.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/telemetry/contract.d.ts +90 -0
- package/dist/telemetry/contract.d.ts.map +1 -0
- package/dist/telemetry/contract.js +203 -0
- package/dist/telemetry/contract.js.map +1 -0
- package/dist/telemetry/flush.d.ts +21 -0
- package/dist/telemetry/flush.d.ts.map +1 -0
- package/dist/telemetry/flush.js +84 -0
- package/dist/telemetry/flush.js.map +1 -0
- package/dist/telemetry/gate.d.ts +16 -0
- package/dist/telemetry/gate.d.ts.map +1 -0
- package/dist/telemetry/gate.js +64 -0
- package/dist/telemetry/gate.js.map +1 -0
- package/dist/telemetry/identity.d.ts +33 -0
- package/dist/telemetry/identity.d.ts.map +1 -0
- package/dist/telemetry/identity.js +80 -0
- package/dist/telemetry/identity.js.map +1 -0
- package/dist/telemetry/index.d.ts +18 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js +16 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/key.d.ts +21 -0
- package/dist/telemetry/key.d.ts.map +1 -0
- package/dist/telemetry/key.js +49 -0
- package/dist/telemetry/key.js.map +1 -0
- package/dist/telemetry/notice.d.ts +19 -0
- package/dist/telemetry/notice.d.ts.map +1 -0
- package/dist/telemetry/notice.js +90 -0
- package/dist/telemetry/notice.js.map +1 -0
- package/dist/telemetry/queue.d.ts +35 -0
- package/dist/telemetry/queue.d.ts.map +1 -0
- package/dist/telemetry/queue.js +162 -0
- package/dist/telemetry/queue.js.map +1 -0
- package/dist/telemetry/send.d.ts +19 -0
- package/dist/telemetry/send.d.ts.map +1 -0
- package/dist/telemetry/send.js +84 -0
- package/dist/telemetry/send.js.map +1 -0
- package/dist/telemetry/sessions.d.ts +8 -0
- package/dist/telemetry/sessions.d.ts.map +1 -0
- package/dist/telemetry/sessions.js +81 -0
- package/dist/telemetry/sessions.js.map +1 -0
- package/dist/telemetry/track.d.ts +43 -0
- package/dist/telemetry/track.d.ts.map +1 -0
- package/dist/telemetry/track.js +108 -0
- package/dist/telemetry/track.js.map +1 -0
- package/dist/upkeep-run.d.ts +15 -0
- package/dist/upkeep-run.d.ts.map +1 -0
- package/dist/upkeep-run.js +60 -0
- package/dist/upkeep-run.js.map +1 -0
- package/dist/upkeep.d.ts +114 -0
- package/dist/upkeep.d.ts.map +1 -0
- package/dist/upkeep.js +232 -0
- package/dist/upkeep.js.map +1 -0
- package/dist/util/num.d.ts +3 -0
- package/dist/util/num.d.ts.map +1 -0
- package/dist/util/num.js +20 -0
- package/dist/util/num.js.map +1 -0
- package/dist/util/state.d.ts +11 -4
- package/dist/util/state.d.ts.map +1 -1
- package/dist/util/state.js +9 -0
- package/dist/util/state.js.map +1 -1
- package/dist/viewer/app.js +1 -1
- package/dist/viewer/index.html +1 -0
- package/dist/viewer/style.css +23 -2
- package/dist/viz/assemble.d.ts +33 -0
- package/dist/viz/assemble.d.ts.map +1 -1
- package/dist/viz/assemble.js.map +1 -1
- package/dist/viz/export.d.ts +39 -0
- package/dist/viz/export.d.ts.map +1 -0
- package/dist/viz/export.js +98 -0
- package/dist/viz/export.js.map +1 -0
- package/package.json +15 -5
- package/scripts/stamp-telemetry-key.mjs +53 -0
package/dist/ask/fuse.js
CHANGED
|
@@ -1,27 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Scope-aware ranking for `graft ask
|
|
3
|
-
* fusion (RRF). Pure functions, no fs.
|
|
2
|
+
* Scope-aware ranking for `graft ask`. Pure functions, no fs.
|
|
4
3
|
*
|
|
5
4
|
* The problem: lexical + graph scores are corpus-relative. In a multi-scope
|
|
6
5
|
* repo (a monorepo's `frontend/` + `backend/`, sub-projects under one root),
|
|
7
|
-
*
|
|
8
|
-
* score scale and drown the small one
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* scoring every node against one pooled corpus lets the biggest sub-project set
|
|
7
|
+
* the score scale and drown the small one.
|
|
8
|
+
*
|
|
9
|
+
* This module solves it by keeping the scope PARTITION — each scope is scored
|
|
10
|
+
* and walked separately — while making the resulting scores COMPARABLE, so the
|
|
11
|
+
* combined order can be read straight off the score. Comparability has two
|
|
12
|
+
* requirements, and both must hold or the order is meaningless:
|
|
13
|
+
*
|
|
14
|
+
* 1. shared corpus statistics — the caller scores every scope against the
|
|
15
|
+
* repo-wide IDF and length prior (see `ask.ts`), so the same term is worth
|
|
16
|
+
* the same everywhere;
|
|
17
|
+
* 2. a shared normalization denominator — {@link rankScopesAndFuse} divides
|
|
18
|
+
* every scope by the best raw score in the REPO, not by each scope's own
|
|
19
|
+
* best (see `globalMaxLex` there).
|
|
20
|
+
*
|
|
21
|
+
* Issue #117 was the consequence of neither holding. Each scope divided by its
|
|
22
|
+
* own maximum, so a barely-relevant scope's top hit normalized to ~1.0 exactly
|
|
23
|
+
* like the genuinely relevant scope's top hit; RRF then fused by RANK, which
|
|
24
|
+
* discards magnitude outright, so the weak scope's rank-1 tied the strong
|
|
25
|
+
* scope's rank-1 and displaced its rank-2 — frequently the answer. Measurement
|
|
26
|
+
* across four repositories and four ecosystems put 73% of missed files in that
|
|
27
|
+
* bucket. RRF is retained for `federateAsk` (see `graph/workspace.ts`), where
|
|
28
|
+
* the corpora really are separate repositories and no shared denominator
|
|
29
|
+
* exists — that is the case rank fusion is for.
|
|
13
30
|
*
|
|
14
31
|
* Soft federation: a scope whose top hit is probably an incidental word
|
|
15
|
-
* collision, not a second home for the query, is left out of the
|
|
32
|
+
* collision, not a second home for the query, is left out of the combined order
|
|
16
33
|
* and reported in `alsoMatched` instead, so the output can say "also matched:
|
|
17
|
-
* docs/ — narrow with --in docs/" rather than diluting the pack.
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
34
|
+
* docs/ — narrow with --in docs/" rather than diluting the pack. With
|
|
35
|
+
* comparable scores that gate is simply {@link PARTICIPATION_RATIO} — a scope
|
|
36
|
+
* must reach a real share of the best score anywhere in the repo. Under
|
|
37
|
+
* per-scope normalization that check was vacuous (every scope's top was ~1.0),
|
|
38
|
+
* which is why a separate match-STRENGTH gate ({@link STRONG_FLOOR}/{@link
|
|
39
|
+
* HIGH_FLOOR}) had to stand in for it; that signal is still exported and still
|
|
40
|
+
* used by `federateAsk`, which normalizes per child repo and therefore still
|
|
41
|
+
* needs it.
|
|
25
42
|
*/
|
|
26
43
|
/** RRF smoothing constant — the standard value from the original RRF paper;
|
|
27
44
|
* high enough that rank 1 vs 2 differ gently rather than by 2×. */
|
|
@@ -135,25 +152,99 @@ export function fuseScopes(docs) {
|
|
|
135
152
|
ranked.sort((a, b) => b.score - a.score || a.scope.localeCompare(b.scope) || a.id.localeCompare(b.id));
|
|
136
153
|
return { ranked, federated, alsoMatched };
|
|
137
154
|
}
|
|
155
|
+
/**
|
|
156
|
+
* Combine scopes whose scores are ALREADY comparable (shared corpus statistics
|
|
157
|
+
* and a shared normalization denominator — see the module header). Same shape
|
|
158
|
+
* and same gate as {@link fuseScopes}, but the combined order is read straight
|
|
159
|
+
* off the score instead of from reciprocal rank, because with a common scale
|
|
160
|
+
* the magnitude is exactly the signal rank fusion would throw away.
|
|
161
|
+
*
|
|
162
|
+
* Only {@link rankScopesAndFuse} may call this. `federateAsk` fuses separate
|
|
163
|
+
* repositories, which have no common denominator, and must keep using
|
|
164
|
+
* {@link fuseScopes}.
|
|
165
|
+
*/
|
|
166
|
+
export function combineComparableScopes(docs) {
|
|
167
|
+
const byScope = new Map();
|
|
168
|
+
for (const d of docs) {
|
|
169
|
+
if (d.score <= 0)
|
|
170
|
+
continue;
|
|
171
|
+
const list = byScope.get(d.scope);
|
|
172
|
+
if (list)
|
|
173
|
+
list.push(d);
|
|
174
|
+
else
|
|
175
|
+
byScope.set(d.scope, [d]);
|
|
176
|
+
}
|
|
177
|
+
for (const list of byScope.values())
|
|
178
|
+
list.sort(byScore);
|
|
179
|
+
if (byScope.size === 0)
|
|
180
|
+
return { ranked: [], federated: [], alsoMatched: [] };
|
|
181
|
+
// One scoring scope: pass through untouched. Identical to the single-scope
|
|
182
|
+
// path by construction — the guarantee that a single-scope repo cannot move.
|
|
183
|
+
if (byScope.size === 1) {
|
|
184
|
+
const [scope, list] = byScope.entries().next().value;
|
|
185
|
+
return {
|
|
186
|
+
ranked: list.map((d) => ({ id: d.id, scope, score: d.score })),
|
|
187
|
+
federated: [scope],
|
|
188
|
+
alsoMatched: [],
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
// Gate on a real share of the best score in the repo. This is the same
|
|
192
|
+
// ratio check `fuseScopes` runs, but here it MEANS something: the scores
|
|
193
|
+
// being compared share a denominator.
|
|
194
|
+
const scopesByBest = [...byScope.entries()].sort((a, b) => b[1][0].score - a[1][0].score || a[0].localeCompare(b[0]));
|
|
195
|
+
const gate = PARTICIPATION_RATIO * scopesByBest[0][1][0].score;
|
|
196
|
+
const federated = [];
|
|
197
|
+
const alsoMatched = [];
|
|
198
|
+
for (const [scope, list] of scopesByBest) {
|
|
199
|
+
if (list[0].score >= gate)
|
|
200
|
+
federated.push(scope);
|
|
201
|
+
else
|
|
202
|
+
alsoMatched.push({ scope, bestId: list[0].id });
|
|
203
|
+
}
|
|
204
|
+
// An id can only belong to one scope (scope is a path prefix), but keep the
|
|
205
|
+
// defensive max so a duplicate cannot double-count or flip its attribution.
|
|
206
|
+
const acc = new Map();
|
|
207
|
+
for (const scope of federated) {
|
|
208
|
+
for (const d of byScope.get(scope)) {
|
|
209
|
+
const prev = acc.get(d.id);
|
|
210
|
+
if (!prev || d.score > prev.score)
|
|
211
|
+
acc.set(d.id, { scope, score: d.score });
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
let max = 0;
|
|
215
|
+
for (const e of acc.values())
|
|
216
|
+
if (e.score > max)
|
|
217
|
+
max = e.score;
|
|
218
|
+
const ranked = [...acc.entries()].map(([id, e]) => ({
|
|
219
|
+
id,
|
|
220
|
+
scope: e.scope,
|
|
221
|
+
score: max > 0 ? e.score / max : 0,
|
|
222
|
+
}));
|
|
223
|
+
ranked.sort((a, b) => b.score - a.score || a.scope.localeCompare(b.scope) || a.id.localeCompare(b.id));
|
|
224
|
+
return { ranked, federated, alsoMatched };
|
|
225
|
+
}
|
|
138
226
|
/**
|
|
139
227
|
* Multi-scope orchestration for `ask`'s symbol ranking: for each scope, score
|
|
140
|
-
* lexically
|
|
141
|
-
* subgraph, blend exactly like the single-scope path (`lexN +
|
|
142
|
-
* graphWeight·pr`,
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* (no seeds → no walk → no docs).
|
|
228
|
+
* lexically (against the repo-wide statistics the caller supplies), walk the
|
|
229
|
+
* scope's subgraph, blend exactly like the single-scope path (`lexN +
|
|
230
|
+
* graphWeight·pr`, walk-rescued nodes joining above `rescueFloor`), then
|
|
231
|
+
* combine the scopes with {@link combineComparableScopes}. A scope with zero
|
|
232
|
+
* lexical matches contributes nothing (no seeds → no walk → no docs).
|
|
146
233
|
*
|
|
147
|
-
* The
|
|
148
|
-
* `
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
234
|
+
* The one thing that differs from the single-scope path: `lexN` divides by
|
|
235
|
+
* `globalMaxLex`, the best raw lexical score across ALL scopes, rather than by
|
|
236
|
+
* each scope's own best. That shared denominator is what makes the blended
|
|
237
|
+
* scores comparable, and therefore what lets the combined order be read off the
|
|
238
|
+
* score. Dividing per scope — as this did before #117 — pinned every scope's
|
|
239
|
+
* top hit to ~1.0 regardless of how well it matched, which is the defect.
|
|
240
|
+
*
|
|
241
|
+
* Participation is then the {@link PARTICIPATION_RATIO} share check inside
|
|
242
|
+
* {@link combineComparableScopes}: a scope must reach a real fraction of the
|
|
243
|
+
* best score anywhere in the repo, else it is reported in `alsoMatched` for
|
|
244
|
+
* `--in`. The match-STRENGTH floors ({@link STRONG_FLOOR}/{@link HIGH_FLOOR})
|
|
245
|
+
* are no longer applied here — they existed to stand in for a share check that
|
|
246
|
+
* per-scope normalization had made vacuous. `federateAsk` still normalizes per
|
|
247
|
+
* child repo, so it still gates on strength; see `src/graph/workspace.ts`.
|
|
157
248
|
*/
|
|
158
249
|
export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
|
|
159
250
|
// Pass 1: lexical scoring only, per scope.
|
|
@@ -166,9 +257,10 @@ export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
|
|
|
166
257
|
}
|
|
167
258
|
const alsoMatched = [];
|
|
168
259
|
const scoped = [];
|
|
169
|
-
// Per-scope raw best
|
|
170
|
-
//
|
|
260
|
+
// Per-scope raw best, plus the best raw score anywhere in the repo. That
|
|
261
|
+
// repo-wide maximum is the shared denominator every scope normalizes by.
|
|
171
262
|
const meta = new Map();
|
|
263
|
+
let globalMaxLex = 0;
|
|
172
264
|
for (const [scope, lex] of lexByScope) {
|
|
173
265
|
let maxLex = 0, bestId = "";
|
|
174
266
|
for (const [id, v] of lex)
|
|
@@ -178,52 +270,58 @@ export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
|
|
|
178
270
|
}
|
|
179
271
|
if (maxLex <= 0)
|
|
180
272
|
continue;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
273
|
+
meta.set(scope, { lex, maxLex, bestId });
|
|
274
|
+
if (maxLex > globalMaxLex)
|
|
275
|
+
globalMaxLex = maxLex;
|
|
276
|
+
}
|
|
277
|
+
// Body-only suppression. With a shared denominator a weak scope simply
|
|
278
|
+
// scores low, so participation is decided on score in
|
|
279
|
+
// `combineComparableScopes` — no scope is excluded on a share threshold any
|
|
280
|
+
// more. The single exception is a scope in which NO doc matched a query term
|
|
281
|
+
// in a name or path while some other scope did: that is the comment-banner
|
|
282
|
+
// collision (see `hasIdentifierMatch` above), and score cannot separate it
|
|
283
|
+
// from a real match. Only applied when a genuine identifier match exists
|
|
284
|
+
// somewhere, so a query that legitimately matches only prose still returns
|
|
285
|
+
// something.
|
|
286
|
+
const bodyOnly = new Set();
|
|
287
|
+
if (ops.hasIdentifierMatch) {
|
|
288
|
+
const named = new Map();
|
|
289
|
+
for (const scope of meta.keys())
|
|
290
|
+
named.set(scope, ops.hasIdentifierMatch(scope));
|
|
291
|
+
if ([...named.values()].some(Boolean)) {
|
|
292
|
+
for (const [scope, ok] of named)
|
|
293
|
+
if (!ok)
|
|
294
|
+
bodyOnly.add(scope);
|
|
295
|
+
}
|
|
185
296
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
// floor and make `ask` return nothing — measurably worse than grep. When the
|
|
190
|
-
// gate would exclude every scope yet real matches exist, keep the single
|
|
191
|
-
// strongest scope so `ask` returns best-effort hits (the escalation nudge
|
|
192
|
-
// already tells the agent to switch to grep if they look weak) instead of
|
|
193
|
-
// abstaining. The gate still does its real job — suppressing a weak scope
|
|
194
|
-
// beside a strong one — whenever any scope passes.
|
|
195
|
-
if (survivors.length === 0 && meta.size > 0) {
|
|
196
|
-
// Tiebreak on scale-invariant match STRENGTH (not raw per-corpus maxLex,
|
|
197
|
-
// which would let the biggest scope's numerically-larger score win — the very
|
|
198
|
-
// cross-corpus scale bias RRF exists to avoid). Fall back to maxLex only when
|
|
199
|
-
// strength ties (e.g. all zero), then scope name for determinism.
|
|
200
|
-
survivors.push([...meta.entries()].sort((a, b) => b[1].strength - a[1].strength || b[1].maxLex - a[1].maxLex || a[0].localeCompare(b[0]))[0][0]);
|
|
297
|
+
for (const scope of bodyOnly) {
|
|
298
|
+
alsoMatched.push({ scope, bestId: meta.get(scope).bestId });
|
|
299
|
+
meta.delete(scope);
|
|
201
300
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
for (const
|
|
206
|
-
|
|
301
|
+
// The denominator must come from the scopes that actually rank, or a
|
|
302
|
+
// suppressed scope could still set the scale for everyone else.
|
|
303
|
+
globalMaxLex = 0;
|
|
304
|
+
for (const { maxLex } of meta.values())
|
|
305
|
+
if (maxLex > globalMaxLex)
|
|
306
|
+
globalMaxLex = maxLex;
|
|
307
|
+
for (const [scope, { lex }] of meta) {
|
|
207
308
|
const pr = ops.walk(scope, lex);
|
|
208
309
|
const candidates = new Set(lex.keys());
|
|
209
310
|
for (const [id, p] of pr)
|
|
210
311
|
if (p >= rescueFloor)
|
|
211
312
|
candidates.add(id);
|
|
212
313
|
for (const id of candidates) {
|
|
213
|
-
const lexN =
|
|
314
|
+
const lexN = globalMaxLex > 0 ? (lex.get(id) ?? 0) / globalMaxLex : 0;
|
|
214
315
|
const blended = (lexN + graphWeight * (pr.get(id) ?? 0)) * (ops.rankFactor?.(scope, id) ?? 1);
|
|
215
316
|
if (blended > 0)
|
|
216
317
|
scoped.push({ id, scope, score: blended });
|
|
217
318
|
}
|
|
218
319
|
}
|
|
219
|
-
|
|
220
|
-
// normalized) input — left as-is per its pure-test contract; it's now
|
|
221
|
-
// effectively a no-op safety net rather than the real gate.
|
|
222
|
-
const fused = fuseScopes(scoped);
|
|
320
|
+
const combined = combineComparableScopes(scoped);
|
|
223
321
|
return {
|
|
224
|
-
ranked:
|
|
225
|
-
federated:
|
|
226
|
-
alsoMatched: [...alsoMatched, ...
|
|
322
|
+
ranked: combined.ranked,
|
|
323
|
+
federated: combined.federated,
|
|
324
|
+
alsoMatched: [...alsoMatched, ...combined.alsoMatched],
|
|
227
325
|
};
|
|
228
326
|
}
|
|
229
327
|
//# sourceMappingURL=fuse.js.map
|
package/dist/ask/fuse.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type BlastFormat = "text" | "markdown" | "mermaid" | "json";
|
|
2
|
+
export interface BlastCliOptions {
|
|
3
|
+
/** Base ref to diff against (`origin/main`); omitted → working tree vs HEAD. */
|
|
4
|
+
base?: string;
|
|
5
|
+
/** Raw `--depth`: a positive integer, or `all`/`full`/`max`. Default 2. */
|
|
6
|
+
depth?: string;
|
|
7
|
+
format?: string;
|
|
8
|
+
/** Ask a model to name the clusters that have no concept name (one call, cached).
|
|
9
|
+
* Opt-in: a local `graft blast` must not need a key or a network round-trip. */
|
|
10
|
+
name?: boolean;
|
|
11
|
+
/** Write the interactive page for this radius here (one self-contained file). */
|
|
12
|
+
exportViz?: string;
|
|
13
|
+
/** Subtitle beside the repo name on the exported page, e.g. "PR #171". Same
|
|
14
|
+
* meaning as `graft viz --title`. Without it a reader of a published page has no
|
|
15
|
+
* way to tell which pull request they are looking at. */
|
|
16
|
+
title?: string;
|
|
17
|
+
/** The top-level `--dir` override. */
|
|
18
|
+
globalDir?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function runBlastCommand(dir: string, opts: BlastCliOptions): Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* What to call the repository in the appbar.
|
|
23
|
+
*
|
|
24
|
+
* `basename(root)` is right for someone running this in their own clone, but CI
|
|
25
|
+
* checks a pull request out into a directory named for the job — ours is literally
|
|
26
|
+
* `pr` — which titled the published page "pr". The origin remote is the repository,
|
|
27
|
+
* so it wins when there is one; a detached tarball checkout still falls back.
|
|
28
|
+
*/
|
|
29
|
+
export declare function repoLabel(root: string): string;
|
|
30
|
+
//# sourceMappingURL=blast-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blast-cli.d.ts","sourceRoot":"","sources":["../../src/blast/blast-cli.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;oFACgF;IAChF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;6DAEyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CvF;AAsCD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY9C"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI wiring for `graft blast` — the command a CI job runs on a pull request.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of cli.ts (argument wiring only) so the diff → seeds → walk → render
|
|
5
|
+
* chain stays unit-testable without shelling out, matching `graph/traverse-cli.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
import { basename, resolve } from "node:path";
|
|
9
|
+
import { contextDirFor } from "../context/node-file.js";
|
|
10
|
+
import { loadGraphCached } from "../graph/load.js";
|
|
11
|
+
import { blastRadiusIn } from "./blast.js";
|
|
12
|
+
import { changedFiles, refExists } from "./diff.js";
|
|
13
|
+
import { markdownReport, mermaidDiagram, textReport } from "./render.js";
|
|
14
|
+
const DEFAULT_DEPTH = 2;
|
|
15
|
+
function resolveFormat(raw) {
|
|
16
|
+
if (raw === undefined)
|
|
17
|
+
return "text";
|
|
18
|
+
if (raw === "text" || raw === "markdown" || raw === "mermaid" || raw === "json")
|
|
19
|
+
return raw;
|
|
20
|
+
console.error(`✗ --format must be text, markdown, mermaid or json, got "${raw}"`);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
/** Same grammar as `graft callers --depth`, so the two commands stay learnable together. */
|
|
24
|
+
function resolveDepth(raw) {
|
|
25
|
+
if (raw === undefined)
|
|
26
|
+
return DEFAULT_DEPTH;
|
|
27
|
+
if (/^(all|full|max)$/i.test(raw))
|
|
28
|
+
return Number.POSITIVE_INFINITY;
|
|
29
|
+
const d = Number(raw);
|
|
30
|
+
if (!Number.isFinite(d) || d < 1) {
|
|
31
|
+
console.error(`✗ --depth must be a positive number or "all", got "${raw}"`);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
return Math.floor(d);
|
|
35
|
+
}
|
|
36
|
+
export async function runBlastCommand(dir, opts) {
|
|
37
|
+
const root = resolve(dir);
|
|
38
|
+
const contextDir = contextDirFor(root, opts.globalDir);
|
|
39
|
+
const format = resolveFormat(opts.format);
|
|
40
|
+
const depth = resolveDepth(opts.depth);
|
|
41
|
+
const graph = loadGraphCached(contextDir);
|
|
42
|
+
if (!graph) {
|
|
43
|
+
console.error(`✗ no graph found at ${contextDir} — run \`graft build\` first`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
// An unknown base is the most common CI misconfiguration by a distance: an
|
|
47
|
+
// `actions/checkout` without `fetch-depth: 0` leaves the base branch absent, and
|
|
48
|
+
// git's own message ("unknown revision or path not in the working tree") sends
|
|
49
|
+
// people looking for a typo instead of the checkout depth.
|
|
50
|
+
if (opts.base !== undefined && !refExists(root, opts.base)) {
|
|
51
|
+
console.error(`✗ base ref "${opts.base}" is not in this checkout.\n` +
|
|
52
|
+
" In CI, fetch enough history for the merge base: actions/checkout with `fetch-depth: 0`.");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const diff = changedFiles(root, opts.base);
|
|
56
|
+
if (!diff) {
|
|
57
|
+
console.error(`✗ could not read a diff in ${root} — is this a git repository?`);
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
const report = blastRadiusIn(graph, contextDir, diff.files, diff.basis, depth);
|
|
61
|
+
if (opts.name)
|
|
62
|
+
await nameClusters(graph, report, contextDir);
|
|
63
|
+
if (opts.exportViz)
|
|
64
|
+
await exportRadius(report, contextDir, root, opts.exportViz, opts.title);
|
|
65
|
+
if (format === "json") {
|
|
66
|
+
console.log(JSON.stringify(report, null, 2));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (format === "mermaid") {
|
|
70
|
+
const diagram = mermaidDiagram(report);
|
|
71
|
+
// Exit 0 with a comment, not an error: "nothing depends on this diff" is a
|
|
72
|
+
// legitimate answer, and a CI step must not fail on it.
|
|
73
|
+
console.log(diagram ?? "%% no dependents to draw");
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
process.stdout.write(format === "markdown" ? markdownReport(report) : textReport(report));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Name the clusters left on their symbol backstop, then report what it cost.
|
|
80
|
+
*
|
|
81
|
+
* Everything here is best-effort by construction: no key, a spent quota or a
|
|
82
|
+
* refused call leaves the backstop labels in place and the command still exits 0,
|
|
83
|
+
* because a PR check must not fail over a cosmetic layer.
|
|
84
|
+
*/
|
|
85
|
+
async function nameClusters(graph, report, contextDir) {
|
|
86
|
+
const { applyNames, ChatNamer } = await import("./name.js");
|
|
87
|
+
const { resolveConfig } = await import("../ai/providers.js");
|
|
88
|
+
const cfg = resolveConfig({ contextDir });
|
|
89
|
+
let namer;
|
|
90
|
+
if (cfg.chatModel) {
|
|
91
|
+
namer = new ChatNamer(cfg.chatModel);
|
|
92
|
+
}
|
|
93
|
+
else if (cfg.apiKey) {
|
|
94
|
+
const { createChatModel } = await import("../ai/llm/factory.js");
|
|
95
|
+
namer = new ChatNamer(createChatModel({
|
|
96
|
+
provider: cfg.provider, apiKey: cfg.apiKey, model: cfg.model,
|
|
97
|
+
baseUrl: cfg.baseUrl, headers: cfg.headers,
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
const stats = await applyNames(graph, report, { namer, contextDir });
|
|
101
|
+
if (!namer) {
|
|
102
|
+
console.error("• --name: no API key (GRAFT_API_KEY), so areas keep their symbol names");
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (stats.error)
|
|
106
|
+
console.error(`• --name: naming failed (${stats.error}) — areas keep their symbol names`);
|
|
107
|
+
else if (stats.named + stats.cached + stats.declined > 0) {
|
|
108
|
+
const bits = [`${stats.named} named`, `${stats.cached} cached`];
|
|
109
|
+
if (stats.declined > 0)
|
|
110
|
+
bits.push(`${stats.declined} left as symbols (mixed)`);
|
|
111
|
+
console.error(`• --name: ${bits.join(", ")}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* What to call the repository in the appbar.
|
|
116
|
+
*
|
|
117
|
+
* `basename(root)` is right for someone running this in their own clone, but CI
|
|
118
|
+
* checks a pull request out into a directory named for the job — ours is literally
|
|
119
|
+
* `pr` — which titled the published page "pr". The origin remote is the repository,
|
|
120
|
+
* so it wins when there is one; a detached tarball checkout still falls back.
|
|
121
|
+
*/
|
|
122
|
+
export function repoLabel(root) {
|
|
123
|
+
try {
|
|
124
|
+
const url = execFileSync("git", ["-C", root, "remote", "get-url", "origin"], {
|
|
125
|
+
encoding: "utf8",
|
|
126
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
127
|
+
}).trim();
|
|
128
|
+
const name = url.replace(/\.git$/, "").split(/[/:]/).pop();
|
|
129
|
+
if (name)
|
|
130
|
+
return name;
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// No remote, or no git at all: the directory name is the best guess left.
|
|
134
|
+
}
|
|
135
|
+
return basename(root);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Write the interactive page for this radius: the same viewer `graft viz` serves,
|
|
139
|
+
* with the blast graph as its Context tab.
|
|
140
|
+
*
|
|
141
|
+
* Done here rather than in `viz` because the radius is what a reviewer opened the
|
|
142
|
+
* link for, and only `blast` has it — `viz --export` on its own can offer the deep
|
|
143
|
+
* tier's concept map, which a PR build no longer produces.
|
|
144
|
+
*/
|
|
145
|
+
async function exportRadius(report, contextDir, root, outDir, subtitle) {
|
|
146
|
+
const { resolve: resolvePath } = await import("node:path");
|
|
147
|
+
const { fileURLToPath } = await import("node:url");
|
|
148
|
+
const { exportViz } = await import("../viz/export.js");
|
|
149
|
+
const { blastVizGraph } = await import("./viz.js");
|
|
150
|
+
const out = exportViz({
|
|
151
|
+
contextDir,
|
|
152
|
+
viewerDir: fileURLToPath(new URL("../viewer/", import.meta.url)), // prebuilt, ships in dist
|
|
153
|
+
outDir: resolvePath(outDir),
|
|
154
|
+
repoName: repoLabel(root),
|
|
155
|
+
subtitle,
|
|
156
|
+
contextGraph: blastVizGraph(report, { root }),
|
|
157
|
+
// Context alone: see VizExportOptions.tabs — the other two tabs are about the
|
|
158
|
+
// repository, and this page is about one pull request.
|
|
159
|
+
tabs: ["context"],
|
|
160
|
+
});
|
|
161
|
+
console.error(`• --export-viz: ${out.file} (${Math.round(out.bytes / 1024)} kB, ${out.contextNodes} areas, ${out.codeNodes} code nodes)`);
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=blast-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blast-cli.js","sourceRoot":"","sources":["../../src/blast/blast-cli.ts"],"names":[],"mappings":"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"}
|