@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/dist/ask/fuse.d.ts
CHANGED
|
@@ -11,11 +11,17 @@
|
|
|
11
11
|
* with RRF — rank positions are comparable across corpora where raw scores
|
|
12
12
|
* are not, so the tiny scope's best hit lands next to the huge scope's best.
|
|
13
13
|
*
|
|
14
|
-
* Soft federation: a scope whose
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* 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 fused order
|
|
16
|
+
* and reported in `alsoMatched` instead, so the output can say "also matched:
|
|
17
|
+
* docs/ — narrow with --in docs/" rather than diluting the pack. The REAL
|
|
18
|
+
* participation gate — used by both `rankScopesAndFuse` here and `federateAsk`
|
|
19
|
+
* (workspace federation) — is the match-STRENGTH signal in {@link
|
|
20
|
+
* STRONG_FLOOR}/{@link HIGH_FLOOR}: a scope's top hit must have matched a
|
|
21
|
+
* query term in a NAME/PATH field, or have broad enough overall coverage to be
|
|
22
|
+
* real even body-only. `fuseScopes`'s own {@link PARTICIPATION_RATIO} gate is
|
|
23
|
+
* a separate, cruder ratio check that still runs internally as a
|
|
24
|
+
* post-normalization safety net, not the primary defense.
|
|
19
25
|
*/
|
|
20
26
|
/** One scored document, attributed to the ranking scope (path prefix, "" =
|
|
21
27
|
* root) it was scored within. Scores must be per-scope-normalized (each
|
|
@@ -47,8 +53,32 @@ export interface FusionResult {
|
|
|
47
53
|
* high enough that rank 1 vs 2 differ gently rather than by 2×. */
|
|
48
54
|
export declare const RRF_K = 60;
|
|
49
55
|
/** A scope federates only when its best doc scores at least this share of the
|
|
50
|
-
* global best — below it the match is reported, not fused.
|
|
56
|
+
* global best — below it the match is reported, not fused. Used by
|
|
57
|
+
* `fuseScopes`'s own internal gate (a post-normalization safety net once a
|
|
58
|
+
* caller has already applied the real match-strength gate — see
|
|
59
|
+
* {@link STRONG_FLOOR}/{@link HIGH_FLOOR}). */
|
|
51
60
|
export declare const PARTICIPATION_RATIO = 0.25;
|
|
61
|
+
/** The single source of truth for the cross-scope participation gate shared
|
|
62
|
+
* by `rankScopesAndFuse` (single-graph multi-scope) and `federateAsk`
|
|
63
|
+
* (workspace federation, `src/graph/workspace.ts`) — the two paths that solve
|
|
64
|
+
* the identical "a weak scope must not federate beside a strong one" problem.
|
|
65
|
+
* They MUST use the same floors so they can never drift into inconsistent
|
|
66
|
+
* behavior again.
|
|
67
|
+
*
|
|
68
|
+
* A scope federates iff its top hit matched a query term in a NAME/PATH field
|
|
69
|
+
* at all (any strength ≥ `STRONG_FLOOR`) — the primary gate. Well below every
|
|
70
|
+
* genuine fixture (≥0.45) yet strictly above a body-only collision's 0, so a
|
|
71
|
+
* real partial-relevance hit on a common/low-idf term is never overcorrected
|
|
72
|
+
* out. */
|
|
73
|
+
export declare const STRONG_FLOOR = 0.1;
|
|
74
|
+
/** …OR the overall (name+path+body) coverage is broad enough to be real even
|
|
75
|
+
* body-only. A single incidental body-token collision measures ~0.29 and RISES
|
|
76
|
+
* with corpus size (0.30+ at 200 nodes) but never approaches this, while a
|
|
77
|
+
* genuinely broad match clears it. This is why the gate is on absolute,
|
|
78
|
+
* scale-invariant floors, NOT a raw-lexical-score ratio (which — calibrated for
|
|
79
|
+
* raw-lexical-SCORE space — was far too lenient in coverage/matched-fraction
|
|
80
|
+
* space and leaked junk, worsening as the corpus grew). */
|
|
81
|
+
export declare const HIGH_FLOOR = 0.5;
|
|
52
82
|
/**
|
|
53
83
|
* Partition by scope, rank within scope (input scores are already
|
|
54
84
|
* per-scope-normalized), gate by soft federation, fuse by RRF:
|
|
@@ -69,28 +99,40 @@ export interface ScopeRankOps {
|
|
|
69
99
|
/** Lexical scores for the scope's own docs (positive entries only),
|
|
70
100
|
* computed against the scope's OWN corpus statistics. */
|
|
71
101
|
lex(scope: string): Map<string, number>;
|
|
102
|
+
/** The match-STRENGTH signal for the participation gate, evaluated at one
|
|
103
|
+
* doc id within `scope` (always called on that scope's raw-lex top doc):
|
|
104
|
+
* `coverage` is the idf-weighted matched share over name+path+body;
|
|
105
|
+
* `coverageStrong` is the same over NAME only, with file-kind nodes
|
|
106
|
+
* contributing zero (see `strongShare` in `src/ask/ask.ts`, the function
|
|
107
|
+
* this must be backed by). Computed against the scope's own per-scope idf,
|
|
108
|
+
* same as `lex`. */
|
|
109
|
+
strength(scope: string, id: string): {
|
|
110
|
+
coverage: number;
|
|
111
|
+
coverageStrong: number;
|
|
112
|
+
};
|
|
72
113
|
/** Graph walk restricted to the scope's subgraph, seeded by that scope's
|
|
73
114
|
* lexical scores; returns top-normalized centrality (or an empty map). */
|
|
74
115
|
walk(scope: string, seeds: Map<string, number>): Map<string, number>;
|
|
75
116
|
}
|
|
76
117
|
/**
|
|
77
118
|
* Multi-scope orchestration for `ask`'s symbol ranking: for each scope, score
|
|
78
|
-
* lexically, gate by
|
|
79
|
-
*
|
|
119
|
+
* lexically, gate by match STRENGTH (not a lenient ratio), walk the scope's
|
|
120
|
+
* subgraph, blend exactly like the single-scope path (`lexN +
|
|
80
121
|
* graphWeight·pr`, both per-scope-normalized; walk-rescued nodes join above
|
|
81
122
|
* `rescueFloor`), then fuse the surviving scopes' blended lists with
|
|
82
123
|
* {@link fuseScopes}. A scope with zero lexical matches contributes nothing
|
|
83
124
|
* (no seeds → no walk → no docs).
|
|
84
125
|
*
|
|
85
|
-
* The gate
|
|
86
|
-
*
|
|
87
|
-
* `
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
126
|
+
* The gate is the SAME two-floor signal `federateAsk` (workspace federation,
|
|
127
|
+
* `src/graph/workspace.ts`) uses: a scope participates iff its top hit's
|
|
128
|
+
* `coverageStrong` ≥ {@link STRONG_FLOOR} OR its `coverage` ≥
|
|
129
|
+
* {@link HIGH_FLOOR}. It is evaluated here, on each scope's raw-lex top doc,
|
|
130
|
+
* BEFORE normalization/walk/blend — gated-out scopes never enter the
|
|
131
|
+
* walk/blend/fuse pipeline at all, they go straight to `alsoMatched` with
|
|
132
|
+
* their best raw-lex doc id. (`fuseScopes`'s own internal ratio gate still
|
|
133
|
+
* runs on the survivors' already-normalized input afterward, but since every
|
|
134
|
+
* survivor's blended top is ~1.0 by construction, that gate is now just a
|
|
135
|
+
* no-op safety net rather than the real gate — the real gate is this one.)
|
|
94
136
|
*/
|
|
95
137
|
export declare function rankScopesAndFuse(scopes: string[], ops: ScopeRankOps, graphWeight: number, rescueFloor: number): FusionResult;
|
|
96
138
|
//# sourceMappingURL=fuse.d.ts.map
|
package/dist/ask/fuse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fuse.d.ts","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fuse.d.ts","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH;;8EAE8E;AAC9E,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B;;;mEAG+D;IAC/D,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,yCAAyC;IACzC,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,uGAAuG;IACvG,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAClD;AAED;mEACmE;AACnE,eAAO,MAAM,KAAK,KAAK,CAAC;AAExB;;;;+CAI+C;AAC/C,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC;;;;;;;;;;;UAWU;AACV,eAAO,MAAM,YAAY,MAAM,CAAC;AAChC;;;;;;2DAM2D;AAC3D,eAAO,MAAM,UAAU,MAAM,CAAC;AAQ9B;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,YAAY,CA+D1D;AAED;;;yBAGyB;AACzB,MAAM,WAAW,YAAY;IAC3B;6DACyD;IACzD,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC;;;;;;wBAMoB;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAClF;8EAC0E;IAC1E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACtE;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,YAAY,CAmDd"}
|
package/dist/ask/fuse.js
CHANGED
|
@@ -11,18 +11,48 @@
|
|
|
11
11
|
* with RRF — rank positions are comparable across corpora where raw scores
|
|
12
12
|
* are not, so the tiny scope's best hit lands next to the huge scope's best.
|
|
13
13
|
*
|
|
14
|
-
* Soft federation: a scope whose
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* 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 fused order
|
|
16
|
+
* and reported in `alsoMatched` instead, so the output can say "also matched:
|
|
17
|
+
* docs/ — narrow with --in docs/" rather than diluting the pack. The REAL
|
|
18
|
+
* participation gate — used by both `rankScopesAndFuse` here and `federateAsk`
|
|
19
|
+
* (workspace federation) — is the match-STRENGTH signal in {@link
|
|
20
|
+
* STRONG_FLOOR}/{@link HIGH_FLOOR}: a scope's top hit must have matched a
|
|
21
|
+
* query term in a NAME/PATH field, or have broad enough overall coverage to be
|
|
22
|
+
* real even body-only. `fuseScopes`'s own {@link PARTICIPATION_RATIO} gate is
|
|
23
|
+
* a separate, cruder ratio check that still runs internally as a
|
|
24
|
+
* post-normalization safety net, not the primary defense.
|
|
19
25
|
*/
|
|
20
26
|
/** RRF smoothing constant — the standard value from the original RRF paper;
|
|
21
27
|
* high enough that rank 1 vs 2 differ gently rather than by 2×. */
|
|
22
28
|
export const RRF_K = 60;
|
|
23
29
|
/** A scope federates only when its best doc scores at least this share of the
|
|
24
|
-
* global best — below it the match is reported, not fused.
|
|
30
|
+
* global best — below it the match is reported, not fused. Used by
|
|
31
|
+
* `fuseScopes`'s own internal gate (a post-normalization safety net once a
|
|
32
|
+
* caller has already applied the real match-strength gate — see
|
|
33
|
+
* {@link STRONG_FLOOR}/{@link HIGH_FLOOR}). */
|
|
25
34
|
export const PARTICIPATION_RATIO = 0.25;
|
|
35
|
+
/** The single source of truth for the cross-scope participation gate shared
|
|
36
|
+
* by `rankScopesAndFuse` (single-graph multi-scope) and `federateAsk`
|
|
37
|
+
* (workspace federation, `src/graph/workspace.ts`) — the two paths that solve
|
|
38
|
+
* the identical "a weak scope must not federate beside a strong one" problem.
|
|
39
|
+
* They MUST use the same floors so they can never drift into inconsistent
|
|
40
|
+
* behavior again.
|
|
41
|
+
*
|
|
42
|
+
* A scope federates iff its top hit matched a query term in a NAME/PATH field
|
|
43
|
+
* at all (any strength ≥ `STRONG_FLOOR`) — the primary gate. Well below every
|
|
44
|
+
* genuine fixture (≥0.45) yet strictly above a body-only collision's 0, so a
|
|
45
|
+
* real partial-relevance hit on a common/low-idf term is never overcorrected
|
|
46
|
+
* out. */
|
|
47
|
+
export const STRONG_FLOOR = 0.1;
|
|
48
|
+
/** …OR the overall (name+path+body) coverage is broad enough to be real even
|
|
49
|
+
* body-only. A single incidental body-token collision measures ~0.29 and RISES
|
|
50
|
+
* with corpus size (0.30+ at 200 nodes) but never approaches this, while a
|
|
51
|
+
* genuinely broad match clears it. This is why the gate is on absolute,
|
|
52
|
+
* scale-invariant floors, NOT a raw-lexical-score ratio (which — calibrated for
|
|
53
|
+
* raw-lexical-SCORE space — was far too lenient in coverage/matched-fraction
|
|
54
|
+
* space and leaked junk, worsening as the corpus grew). */
|
|
55
|
+
export const HIGH_FLOOR = 0.5;
|
|
26
56
|
/** Score-desc, id-asc ordering — the id tiebreak is what makes fusion
|
|
27
57
|
* deterministic under input shuffle. */
|
|
28
58
|
function byScore(a, b) {
|
|
@@ -107,38 +137,33 @@ export function fuseScopes(docs) {
|
|
|
107
137
|
}
|
|
108
138
|
/**
|
|
109
139
|
* Multi-scope orchestration for `ask`'s symbol ranking: for each scope, score
|
|
110
|
-
* lexically, gate by
|
|
111
|
-
*
|
|
140
|
+
* lexically, gate by match STRENGTH (not a lenient ratio), walk the scope's
|
|
141
|
+
* subgraph, blend exactly like the single-scope path (`lexN +
|
|
112
142
|
* graphWeight·pr`, both per-scope-normalized; walk-rescued nodes join above
|
|
113
143
|
* `rescueFloor`), then fuse the surviving scopes' blended lists with
|
|
114
144
|
* {@link fuseScopes}. A scope with zero lexical matches contributes nothing
|
|
115
145
|
* (no seeds → no walk → no docs).
|
|
116
146
|
*
|
|
117
|
-
* The gate
|
|
118
|
-
*
|
|
119
|
-
* `
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
147
|
+
* The gate is the SAME two-floor signal `federateAsk` (workspace federation,
|
|
148
|
+
* `src/graph/workspace.ts`) uses: a scope participates iff its top hit's
|
|
149
|
+
* `coverageStrong` ≥ {@link STRONG_FLOOR} OR its `coverage` ≥
|
|
150
|
+
* {@link HIGH_FLOOR}. It is evaluated here, on each scope's raw-lex top doc,
|
|
151
|
+
* BEFORE normalization/walk/blend — gated-out scopes never enter the
|
|
152
|
+
* walk/blend/fuse pipeline at all, they go straight to `alsoMatched` with
|
|
153
|
+
* their best raw-lex doc id. (`fuseScopes`'s own internal ratio gate still
|
|
154
|
+
* runs on the survivors' already-normalized input afterward, but since every
|
|
155
|
+
* survivor's blended top is ~1.0 by construction, that gate is now just a
|
|
156
|
+
* no-op safety net rather than the real gate — the real gate is this one.)
|
|
126
157
|
*/
|
|
127
158
|
export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
|
|
128
|
-
// Pass 1: lexical scoring only, per scope
|
|
129
|
-
// compute the global raw best the gate compares against.
|
|
159
|
+
// Pass 1: lexical scoring only, per scope.
|
|
130
160
|
const lexByScope = new Map();
|
|
131
|
-
let globalRawBest = 0;
|
|
132
161
|
for (const scope of scopes) {
|
|
133
162
|
const lex = ops.lex(scope);
|
|
134
163
|
if (lex.size === 0)
|
|
135
164
|
continue;
|
|
136
165
|
lexByScope.set(scope, lex);
|
|
137
|
-
for (const v of lex.values())
|
|
138
|
-
if (v > globalRawBest)
|
|
139
|
-
globalRawBest = v;
|
|
140
166
|
}
|
|
141
|
-
const gate = PARTICIPATION_RATIO * globalRawBest;
|
|
142
167
|
const alsoMatched = [];
|
|
143
168
|
const scoped = [];
|
|
144
169
|
for (const [scope, lex] of lexByScope) {
|
|
@@ -154,7 +179,8 @@ export function rankScopesAndFuse(scopes, ops, graphWeight, rescueFloor) {
|
|
|
154
179
|
}
|
|
155
180
|
if (maxLex <= 0)
|
|
156
181
|
continue; // no positive-scoring doc — contributes nothing
|
|
157
|
-
|
|
182
|
+
const { coverage, coverageStrong } = ops.strength(scope, bestId);
|
|
183
|
+
if (coverageStrong < STRONG_FLOOR && coverage < HIGH_FLOOR) {
|
|
158
184
|
alsoMatched.push({ scope, bestId });
|
|
159
185
|
continue; // excluded from fusion — no walk, no blend
|
|
160
186
|
}
|
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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAuBH;mEACmE;AACnE,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;AAExB;;;;+CAI+C;AAC/C,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAExC;;;;;;;;;;;UAWU;AACV,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,CAAC;AAChC;;;;;;2DAM2D;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,CAAC;AAE9B;wCACwC;AACxC,SAAS,OAAO,CAAC,CAAY,EAAE,CAAY;IACzC,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CAAC,IAAiB;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YAClB,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC;IAC9E,IAAI,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAA8B,CAAC;QAC9E,OAAO;YACL,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9D,SAAS,EAAE,CAAC,KAAK,CAAC;YAClB,WAAW,EAAE,EAAE;SAChB,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,qEAAqE;IACrE,MAAM,YAAY,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAC9C,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACpE,CAAC;IACF,MAAM,IAAI,GAAG,mBAAmB,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC/D,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAgC,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,YAAY,EAAE,CAAC;QACzC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI;YAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;YAC5C,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,8BAA8B;IAC9B,MAAM,GAAG,GAAG,IAAI,GAAG,EAA8D,CAAC;IAClF,KAAK,MAAM,KAAK,IAAI,SAAS,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnC,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACzC,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3B,IAAI,CAAC,IAAI;gBAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;iBACjE,CAAC;gBACJ,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC;gBAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACtB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;oBACnB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;gBACpB,CAAC;YACH,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,CAAC,KAAK,GAAG,GAAG;YAAE,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC;IAC/D,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAClD,EAAE;QACF,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,GAAG;KACrB,CAAC,CAAC,CAAC;IACJ,MAAM,CAAC,IAAI,CACT,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAC1F,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC5C,CAAC;AAuBD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAgB,EAChB,GAAiB,EACjB,WAAmB,EACnB,WAAmB;IAEnB,2CAA2C;IAC3C,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAC;IAC1D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;YAAE,SAAS;QAC7B,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,WAAW,GAAgC,EAAE,CAAC;IACpD,MAAM,MAAM,GAAgB,EAAE,CAAC;IAE/B,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,UAAU,EAAE,CAAC;QACtC,qEAAqE;QACrE,qEAAqE;QACrE,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,IAAI,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;gBAChD,MAAM,GAAG,CAAC,CAAC;gBACX,MAAM,GAAG,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QACD,IAAI,MAAM,IAAI,CAAC;YAAE,SAAS,CAAC,gDAAgD;QAE3E,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACjE,IAAI,cAAc,GAAG,YAAY,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;YAC3D,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACpC,SAAS,CAAC,2CAA2C;QACvD,CAAC;QAED,gEAAgE;QAChE,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAChC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE;YAAE,IAAI,CAAC,IAAI,WAAW;gBAAE,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACnE,KAAK,MAAM,EAAE,IAAI,UAAU,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,WAAW,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;YACvD,IAAI,OAAO,GAAG,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,uEAAuE;IACvE,sEAAsE;IACtE,4DAA4D;IAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACjC,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,WAAW,EAAE,CAAC,GAAG,WAAW,EAAE,GAAG,KAAK,CAAC,WAAW,CAAC;KACpD,CAAC;AACJ,CAAC"}
|
package/dist/ask/graphrank.d.ts
CHANGED
|
@@ -21,6 +21,12 @@ export interface PageRankOptions {
|
|
|
21
21
|
alpha?: number;
|
|
22
22
|
/** Power-iteration count. 25 is plenty to converge on graphs this size. */
|
|
23
23
|
iters?: number;
|
|
24
|
+
/** Restrict the walk to a subgraph: when present, an edge counts only when
|
|
25
|
+
* BOTH endpoints pass, and only passing ids can hold rank mass or seed
|
|
26
|
+
* weight. Seeds outside the filter are silently ignored (same as a seed
|
|
27
|
+
* naming a non-existent node). Omit for the full-graph walk (unchanged
|
|
28
|
+
* behavior). */
|
|
29
|
+
nodeFilter?: (id: string) => boolean;
|
|
24
30
|
}
|
|
25
31
|
/**
|
|
26
32
|
* Personalized PageRank over the wiring graph.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphrank.d.ts","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,MAAM,WAAW,eAAe;IAC9B;sFACkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"graphrank.d.ts","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAGjD,MAAM,WAAW,eAAe;IAC9B;sFACkF;IAClF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;oBAIgB;IAChB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC;CACtC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,IAAI,GAAE,eAAoB,GACzB,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAgErB"}
|
package/dist/ask/graphrank.js
CHANGED
|
@@ -13,7 +13,11 @@ import { WALK_RELATIONS } from "../graph/relations.js";
|
|
|
13
13
|
export function personalizedPageRank(graph, seeds, opts = {}) {
|
|
14
14
|
const alpha = opts.alpha ?? 0.25;
|
|
15
15
|
const iters = opts.iters ?? 25;
|
|
16
|
-
|
|
16
|
+
// Real node ids, restricted to the subgraph when a filter is given. Every
|
|
17
|
+
// downstream `ids.has(...)` check (edge endpoints, seeds) then naturally
|
|
18
|
+
// stays within the filtered subgraph, so no other site needs to know about
|
|
19
|
+
// `nodeFilter` — the walk simply never sees the excluded nodes or edges.
|
|
20
|
+
const ids = new Set(graph.nodes.map((n) => n.id).filter((id) => !opts.nodeFilter || opts.nodeFilter(id)));
|
|
17
21
|
// Undirected adjacency over walk relations, endpoints restricted to real nodes.
|
|
18
22
|
const adj = new Map();
|
|
19
23
|
const link = (a, b) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graphrank.js","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"graphrank.js","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"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"}
|
package/dist/claude/format.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Stats, SessionState } from './state.js';
|
|
2
2
|
import type { GraphV1, EdgeV1 } from '../graph/types.js';
|
|
3
|
-
export declare function enrichedSegment(s: Stats): string | null;
|
|
4
3
|
export declare function freshnessSegment(s: Stats): string;
|
|
5
4
|
export declare function renderStatusline(stats: Stats | null, session: SessionState | null, ctx: {
|
|
6
5
|
ctxPct: number | null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/claude/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAUzD,wBAAgB,
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/claude/format.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAUzD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAKjD;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,OAAO,EAAE,YAAY,GAAG,IAAI,EAC5B,GAAG,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAC7B,MAAM,EAAE,CAgBV;AAUD,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAIpE;AAED,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAI,GAAG,MAAM,GAAG,IAAI,CAWtF;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAC5B,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxG,kFAAkF;IAClF,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACjD,oFAAoF;IACpF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0BD,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,SAAI,GAAG,MAAM,CAMlE;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,SAAI,GAAG,MAAM,GAAG,IAAI,CAapE;AAED;;;;;+EAK+E;AAC/E,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAKxC;;;;;;iEAMiE;AACjE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,SAAI,GAAG,MAAM,GAAG,IAAI,CAWvF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,WAAW,SAAO,GAAG,MAAM,CAiB7E;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,MAAM,CAItF"}
|
package/dist/claude/format.js
CHANGED
|
@@ -6,12 +6,6 @@ const C = {
|
|
|
6
6
|
text: (s) => `\x1b[38;5;251m${s}\x1b[0m`,
|
|
7
7
|
};
|
|
8
8
|
const SEP = C.muted(' · ');
|
|
9
|
-
export function enrichedSegment(s) {
|
|
10
|
-
if (s.readyCount < 1)
|
|
11
|
-
return null;
|
|
12
|
-
const pct = s.totalCount ? Math.round((s.readyCount / s.totalCount) * 100) : 0;
|
|
13
|
-
return C.indigo(`${pct}% enriched`);
|
|
14
|
-
}
|
|
15
9
|
export function freshnessSegment(s) {
|
|
16
10
|
if (s.syncing)
|
|
17
11
|
return C.amber('syncing…');
|
|
@@ -26,9 +20,6 @@ export function renderStatusline(stats, session, ctx) {
|
|
|
26
20
|
return [C.muted('◤ graft · not built · run ') + C.text('graft build')];
|
|
27
21
|
}
|
|
28
22
|
const top = [C.muted('◤ ') + C.indigo('graft'), C.text(`${stats.nodeCount} nodes / ${stats.edgeCount} edges`)];
|
|
29
|
-
const enr = enrichedSegment(stats);
|
|
30
|
-
if (enr)
|
|
31
|
-
top.push(enr);
|
|
32
23
|
top.push(freshnessSegment(stats));
|
|
33
24
|
const saved = session?.savedTokens ?? 0;
|
|
34
25
|
if (saved > 0)
|
|
@@ -65,7 +56,7 @@ export function formatBlastRadius(w, filePath, cap = 8) {
|
|
|
65
56
|
return ` • ${e.relation} ← ${label}`;
|
|
66
57
|
});
|
|
67
58
|
const more = edges.length > cap ? `\n • +${edges.length - cap} more` : '';
|
|
68
|
-
return `[graft] blast radius for ${basename(filePath)}
|
|
59
|
+
return `[graft] blast radius for ${basename(filePath)}, who depends on it:\n${items.join('\n')}${more}`;
|
|
69
60
|
}
|
|
70
61
|
function tokensOf(chars) { return Math.round(chars / 4); }
|
|
71
62
|
/** The retrieval pack body — pointers, snippets, and (in --source mode) the
|
|
@@ -75,7 +66,7 @@ function retrievalBody(hits) {
|
|
|
75
66
|
const blocks = hits.map((h, i) => {
|
|
76
67
|
const ptr = (h.pointer ?? '').split(',')[0].trim();
|
|
77
68
|
const snip = (h.snippet ?? '').replace(/\s+/g, ' ').trim().slice(0, 140);
|
|
78
|
-
let b = ` ${i + 1}. ${h.title}
|
|
69
|
+
let b = ` ${i + 1}. ${h.title}: ${ptr}`;
|
|
79
70
|
if (snip)
|
|
80
71
|
b += `\n ${snip}`;
|
|
81
72
|
if (h.code)
|
|
@@ -87,8 +78,8 @@ function retrievalBody(hits) {
|
|
|
87
78
|
// pulling spans itself via `graft ask --source` (push→pull: per-prompt injected
|
|
88
79
|
// tokens are always fresh full-price input, so the pack stays tiny).
|
|
89
80
|
const header = hits.some((h) => h.code)
|
|
90
|
-
? '[graft] retrieved context
|
|
91
|
-
: '[graft] starting points for this task
|
|
81
|
+
? '[graft] retrieved context, read these spans; do not re-open the files:'
|
|
82
|
+
: '[graft] starting points for this task: pull the code inline with `graft ask "<what you need>" --source`, trace impact with `graft callers <symbol>`, or search with `graft grep "<literal>"`:';
|
|
92
83
|
return `${header}\n${blocks.join('\n')}`;
|
|
93
84
|
}
|
|
94
85
|
/** Tokens saved (baseline − this pack), or 0 when no honest estimate applies. */
|
|
@@ -110,7 +101,7 @@ export function formatRetrieval(ask, cap = 5) {
|
|
|
110
101
|
return body;
|
|
111
102
|
const base = tokensOf(ask.saved.baselineChars);
|
|
112
103
|
const pct = Math.round((saved / base) * 100);
|
|
113
|
-
return (`${body}\n[graft] tokens saved ≈ ${saved.toLocaleString()} (${pct}%)
|
|
104
|
+
return (`${body}\n[graft] tokens saved ≈ ${saved.toLocaleString()} (${pct}%); this pack ≈ ` +
|
|
114
105
|
`${tokensOf(body.length).toLocaleString()} tok vs reading the ${ask.saved.files} file(s) whole ≈ ` +
|
|
115
106
|
`${base.toLocaleString()} tok (estimate).`);
|
|
116
107
|
}
|
|
@@ -148,13 +139,19 @@ export function relevantRetrieval(ask, s, cap = 3) {
|
|
|
148
139
|
}
|
|
149
140
|
export function formatOrientation(indexMd, budgetBytes = 1500) {
|
|
150
141
|
// Always-on directive (cached, seen turn 0) so the agent reaches for graft's
|
|
151
|
-
// commands without waiting for the discretionary skill to load.
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
` • graft
|
|
142
|
+
// commands without waiting for the discretionary skill to load. This is the
|
|
143
|
+
// reliable steering channel (fires every session, unlike the discretionary
|
|
144
|
+
// skill): it carries a one-line description of each tool AND the call-discipline
|
|
145
|
+
// that keeps the agent from over-tooling. Positive only, names the tools,
|
|
146
|
+
// forbids nothing.
|
|
147
|
+
const directive = `[graft] This repo is indexed by graft. To find, understand, or change code, reach for graft first; it answers from a prebuilt graph with exact file:line, faster than grep/read. Pick the ONE tool that fits and act on its answer. Most tasks need a single call. If one isn't enough, switch to the tool that fits the next need; don't call the same tool again and again or re-ask a question reworded:\n` +
|
|
148
|
+
` • graft ask "<task>" --source: locate + understand. Ranked nodes with the code inlined at each file:line (the ≤8-line crux; add --full for the whole span). The default for "how does X work" / "where is Y".\n` +
|
|
149
|
+
` • graft grep "<literal>": exhaustive find. Every occurrence, grouped by enclosing symbol; use when you need them ALL (ask is ranked top-N and misses instances).\n` +
|
|
150
|
+
` • graft skeleton <file>: a file's whole API in ~200 tokens, every signature + span, ~10x cheaper than reading the file.\n` +
|
|
151
|
+
` • graft callers <sym> [--direction out] [--depth N]: exact edges. Who calls it (default), what it calls (--direction out), or the full blast radius (--depth 2). Run before you change a symbol.\n` +
|
|
152
|
+
` • graft map: orientation for an unfamiliar repo, directory clusters, hubs, hotspots. map alone is the answer; don't then skeleton every subsystem it names.\n` +
|
|
153
|
+
` In a monorepo, add --in <path>/ to ask/grep/callers to scope to one sub-project; hits are labeled [scope/].\n` +
|
|
154
|
+
`Each tool prints a "[graft] tokens saved ≈ N" footer; when you used graft this turn, close your reply with a one-line tally of the total saved (e.g. 🌱 graft saved ~12k tokens this turn, 3 calls).\n`;
|
|
158
155
|
return `${directive}\nrepo map (graft/INDEX.md):\n${indexMd.slice(0, budgetBytes)}`;
|
|
159
156
|
}
|
|
160
157
|
export function renderSubagent(agentName, session) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/claude/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAIrC,MAAM,CAAC,GAAG;IACR,MAAM,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,wBAAwB,CAAC,SAAS;IACzD,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,wBAAwB,CAAC,SAAS;IACxD,KAAK,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS;IACjD,IAAI,EAAE,CAAC,CAAS,EAAE,EAAE,CAAC,iBAAiB,CAAC,SAAS;CACjD,CAAC;AACF,MAAM,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAE3B,MAAM,UAAU,
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/claude/format.ts"],"names":[],"mappings":"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"}
|
package/dist/claude/hooks.d.ts
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
1
|
export declare function underGraft(dir: string, file: string): boolean;
|
|
2
|
+
/**
|
|
3
|
+
* The "you're working in backend/, weight it" hint: on a multi-scope repo,
|
|
4
|
+
* narrow the prompt hook's `ask` call to whatever scope the last-edited file
|
|
5
|
+
* (`stats.lastFile`, captured at {@link handlePostEdit}) sits in.
|
|
6
|
+
*
|
|
7
|
+
* `lastFile` is only a basename (not a repo-relative path — see
|
|
8
|
+
* `handlePostEdit`), so this is a best-effort lookup against the CURRENT
|
|
9
|
+
* graph: any file node whose path ends in `/<lastFile>` (or equals it, for a
|
|
10
|
+
* repo-root file). Fails soft in every direction a hook must never crash on —
|
|
11
|
+
* no graph, a single-scope graph, a lastFile no longer in the graph (moved,
|
|
12
|
+
* deleted, or edited before the first build), or a basename that lands in
|
|
13
|
+
* more than one scope (ambiguous: could be either sub-project) all skip the
|
|
14
|
+
* hint silently, logging one line to stderr so the miss is visible without
|
|
15
|
+
* ever failing the hook.
|
|
16
|
+
*/
|
|
17
|
+
export declare function lastFileScopeHint(dir: string, lastFile: string | null | undefined): string | null;
|
|
2
18
|
export declare function main(event: string): Promise<void>;
|
|
3
19
|
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/claude/hooks.ts"],"names":[],"mappings":"AAwBA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7D;AAqCD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAyBjG;AAoCD,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CvD"}
|
package/dist/claude/hooks.js
CHANGED
|
@@ -5,6 +5,7 @@ import { readWiring } from './stats.js';
|
|
|
5
5
|
import { formatBlastRadius, relevantRetrieval, formatOrientation } from './format.js';
|
|
6
6
|
import { patchStats, readStats, acquireLock, readSession, writeSession } from './state.js';
|
|
7
7
|
import { graftCliPath, claudeScriptPath } from './paths.js';
|
|
8
|
+
import { scopeOf, scopesOfGraph } from '../graph/scopes.js';
|
|
8
9
|
/** Prompts shorter than this never trigger retrieval — they are almost always
|
|
9
10
|
* conversational ("yes go ahead", "thanks") and the coverage gate can't judge
|
|
10
11
|
* them reliably with so few terms. */
|
|
@@ -34,7 +35,12 @@ export function underGraft(dir, file) {
|
|
|
34
35
|
}
|
|
35
36
|
function graftJson(dir, args) {
|
|
36
37
|
try {
|
|
37
|
-
|
|
38
|
+
// GRAFT_TEST_CLI is a test seam (mirrors GRAFT_TEST_STDIN/GRAFT_TEST_SYNC_RUN) so
|
|
39
|
+
// tests can point the prompt hook's `graft ask`/`graft check` calls at a stub
|
|
40
|
+
// script and observe the exact args it was invoked with, instead of shelling
|
|
41
|
+
// out to the real CLI (which isn't built relative to the TS source under test).
|
|
42
|
+
const cliPath = process.env.GRAFT_TEST_CLI ?? graftCliPath();
|
|
43
|
+
const out = execFileSync(process.execPath, [cliPath, ...args], { cwd: dir, encoding: 'utf8', timeout: 8000, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
38
44
|
return JSON.parse(out);
|
|
39
45
|
}
|
|
40
46
|
catch (e) {
|
|
@@ -69,6 +75,67 @@ async function handlePostEdit(input, dir) {
|
|
|
69
75
|
emit('PostToolUse', br);
|
|
70
76
|
}
|
|
71
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* The "you're working in backend/, weight it" hint: on a multi-scope repo,
|
|
80
|
+
* narrow the prompt hook's `ask` call to whatever scope the last-edited file
|
|
81
|
+
* (`stats.lastFile`, captured at {@link handlePostEdit}) sits in.
|
|
82
|
+
*
|
|
83
|
+
* `lastFile` is only a basename (not a repo-relative path — see
|
|
84
|
+
* `handlePostEdit`), so this is a best-effort lookup against the CURRENT
|
|
85
|
+
* graph: any file node whose path ends in `/<lastFile>` (or equals it, for a
|
|
86
|
+
* repo-root file). Fails soft in every direction a hook must never crash on —
|
|
87
|
+
* no graph, a single-scope graph, a lastFile no longer in the graph (moved,
|
|
88
|
+
* deleted, or edited before the first build), or a basename that lands in
|
|
89
|
+
* more than one scope (ambiguous: could be either sub-project) all skip the
|
|
90
|
+
* hint silently, logging one line to stderr so the miss is visible without
|
|
91
|
+
* ever failing the hook.
|
|
92
|
+
*/
|
|
93
|
+
export function lastFileScopeHint(dir, lastFile) {
|
|
94
|
+
if (!lastFile)
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
const w = readWiring(dir);
|
|
98
|
+
if (!w)
|
|
99
|
+
return null;
|
|
100
|
+
const scopes = scopesOfGraph(w);
|
|
101
|
+
if (scopes.length <= 1)
|
|
102
|
+
return null; // single-scope: no hint, no --in
|
|
103
|
+
const matches = (w.nodes ?? []).filter((n) => n.kind === 'file' && (n.path === lastFile || n.path.endsWith(`/${lastFile}`)));
|
|
104
|
+
if (matches.length === 0) {
|
|
105
|
+
console.error(`[graft] prompt hook: lastFile "${lastFile}" not found in the graph — skipping scope hint`);
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const prefixes = new Set(matches.map((n) => scopeOf(n.path, scopes).prefix));
|
|
109
|
+
if (prefixes.size > 1) {
|
|
110
|
+
console.error(`[graft] prompt hook: lastFile "${lastFile}" matches more than one scope — skipping scope hint`);
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const [prefix] = prefixes;
|
|
114
|
+
return prefix === '' ? null : prefix; // root scope: nothing to narrow
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
console.error(`[graft] prompt hook: scope hint lookup failed (${e?.message ?? e}) — skipping`);
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/** PostToolUse on a graft retrieval tool. Its rendered output carries one (or
|
|
122
|
+
* more) `[graft] tokens saved ≈ N` footers — the same numbers the agent just
|
|
123
|
+
* read. Sum them and add to the session's running total so the statusline's
|
|
124
|
+
* `~N tok saved` reflects what graft saved this session, across CLI and MCP.
|
|
125
|
+
* Pure parse of the payload the hook already received (no re-run), and a no-op
|
|
126
|
+
* unless a footer is present — so it stays cheap on unrelated Bash calls. */
|
|
127
|
+
function handleToolSavings(input, dir) {
|
|
128
|
+
const blob = JSON.stringify(input?.tool_response ?? input ?? '');
|
|
129
|
+
let total = 0;
|
|
130
|
+
for (const m of blob.matchAll(/\[graft\] tokens saved ≈ ([\d,]+)/g))
|
|
131
|
+
total += Number(m[1].replace(/,/g, '')) || 0;
|
|
132
|
+
if (total <= 0)
|
|
133
|
+
return;
|
|
134
|
+
const id = input?.session_id || 'default';
|
|
135
|
+
const s = readSession(dir, id);
|
|
136
|
+
s.savedTokens = (s.savedTokens ?? 0) + total;
|
|
137
|
+
writeSession(dir, id, s);
|
|
138
|
+
}
|
|
72
139
|
function handleStop(dir) {
|
|
73
140
|
// sync-run.js ships next to this module inside the package, so it resolves in
|
|
74
141
|
// any repo that installs graft (not just graft's own). Defensive existsSync:
|
|
@@ -100,6 +167,10 @@ export async function main(event) {
|
|
|
100
167
|
await handlePostEdit(input, dir);
|
|
101
168
|
return;
|
|
102
169
|
}
|
|
170
|
+
if (event === 'tool-savings') {
|
|
171
|
+
handleToolSavings(input, dir);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
103
174
|
if (event === 'stop') {
|
|
104
175
|
handleStop(dir);
|
|
105
176
|
return;
|
|
@@ -119,7 +190,13 @@ export async function main(event) {
|
|
|
119
190
|
// pulls spans itself via `graft ask --source` when a pointer looks right.
|
|
120
191
|
// relevantRetrieval then drops the pack entirely when the prompt barely
|
|
121
192
|
// overlaps the top hit or when every hit was already injected this session.
|
|
122
|
-
const
|
|
193
|
+
const askArgs = ['ask', prompt, '.', '--json', '-n', '3'];
|
|
194
|
+
// "You're working in backend/, weight it": only fires on a multi-scope
|
|
195
|
+
// repo whose lastFile resolves cleanly to one scope — see lastFileScopeHint.
|
|
196
|
+
const scopeHint = lastFileScopeHint(dir, readStats(dir)?.lastFile);
|
|
197
|
+
if (scopeHint)
|
|
198
|
+
askArgs.push('--in', scopeHint);
|
|
199
|
+
const ask = graftJson(dir, askArgs);
|
|
123
200
|
if (!ask)
|
|
124
201
|
return;
|
|
125
202
|
const id = input.session_id || 'default';
|