@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.
Files changed (71) hide show
  1. package/README.md +93 -52
  2. package/dist/ai/llm/types.d.ts +2 -2
  3. package/dist/ai/llm/types.js +1 -1
  4. package/dist/ask/ask.d.ts +49 -1
  5. package/dist/ask/ask.d.ts.map +1 -1
  6. package/dist/ask/ask.js +270 -68
  7. package/dist/ask/ask.js.map +1 -1
  8. package/dist/ask/fuse.d.ts +59 -17
  9. package/dist/ask/fuse.d.ts.map +1 -1
  10. package/dist/ask/fuse.js +51 -25
  11. package/dist/ask/fuse.js.map +1 -1
  12. package/dist/ask/graphrank.d.ts +6 -0
  13. package/dist/ask/graphrank.d.ts.map +1 -1
  14. package/dist/ask/graphrank.js +5 -1
  15. package/dist/ask/graphrank.js.map +1 -1
  16. package/dist/claude/format.d.ts +0 -1
  17. package/dist/claude/format.d.ts.map +1 -1
  18. package/dist/claude/format.js +18 -21
  19. package/dist/claude/format.js.map +1 -1
  20. package/dist/claude/hooks.d.ts +16 -0
  21. package/dist/claude/hooks.d.ts.map +1 -1
  22. package/dist/claude/hooks.js +79 -2
  23. package/dist/claude/hooks.js.map +1 -1
  24. package/dist/claude/settings-merge.d.ts.map +1 -1
  25. package/dist/claude/settings-merge.js +13 -6
  26. package/dist/claude/settings-merge.js.map +1 -1
  27. package/dist/claude/skill-template.d.ts.map +1 -1
  28. package/dist/claude/skill-template.js +117 -76
  29. package/dist/claude/skill-template.js.map +1 -1
  30. package/dist/cli-epilogue.js +1 -1
  31. package/dist/cli-epilogue.js.map +1 -1
  32. package/dist/cli.d.ts +3 -15
  33. package/dist/cli.d.ts.map +1 -1
  34. package/dist/cli.js +79 -45
  35. package/dist/cli.js.map +1 -1
  36. package/dist/context/node-file.d.ts +10 -0
  37. package/dist/context/node-file.d.ts.map +1 -1
  38. package/dist/context/node-file.js +34 -1
  39. package/dist/context/node-file.js.map +1 -1
  40. package/dist/context/savings.d.ts +6 -0
  41. package/dist/context/savings.d.ts.map +1 -1
  42. package/dist/context/savings.js +9 -1
  43. package/dist/context/savings.js.map +1 -1
  44. package/dist/engine.d.ts +1 -0
  45. package/dist/engine.d.ts.map +1 -1
  46. package/dist/engine.js +7 -1
  47. package/dist/engine.js.map +1 -1
  48. package/dist/graph/build.d.ts.map +1 -1
  49. package/dist/graph/build.js +37 -1
  50. package/dist/graph/build.js.map +1 -1
  51. package/dist/graph/map.d.ts +34 -2
  52. package/dist/graph/map.d.ts.map +1 -1
  53. package/dist/graph/map.js +107 -23
  54. package/dist/graph/map.js.map +1 -1
  55. package/dist/graph/types.d.ts +12 -0
  56. package/dist/graph/types.d.ts.map +1 -1
  57. package/dist/graph/workspace-cli.d.ts +37 -0
  58. package/dist/graph/workspace-cli.d.ts.map +1 -0
  59. package/dist/graph/workspace-cli.js +74 -0
  60. package/dist/graph/workspace-cli.js.map +1 -0
  61. package/dist/graph/workspace.d.ts +116 -124
  62. package/dist/graph/workspace.d.ts.map +1 -1
  63. package/dist/graph/workspace.js +353 -297
  64. package/dist/graph/workspace.js.map +1 -1
  65. package/dist/hosts/instructions.d.ts.map +1 -1
  66. package/dist/hosts/instructions.js +3 -0
  67. package/dist/hosts/instructions.js.map +1 -1
  68. package/dist/mcp/tools.d.ts.map +1 -1
  69. package/dist/mcp/tools.js +61 -1
  70. package/dist/mcp/tools.js.map +1 -1
  71. package/package.json +1 -2
@@ -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 best score is far below the global best
15
- * (< {@link PARTICIPATION_RATIO} ×) is probably an incidental word collision,
16
- * not a second home for the query — it is left out of the fused order and
17
- * reported in `alsoMatched` instead, so the output can say "also matched:
18
- * docs/ — narrow with --in docs/" rather than diluting the pack.
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 soft federation on the RAW lexical scores, walk the
79
- * scope's subgraph, blend exactly like the single-scope path (`lexN +
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 MUST run on raw (pre-normalization) lexical scores. `fuseScopes`'s
86
- * own gate compares its input scores, but this function's input to
87
- * `fuseScopes` is already per-scope-normalized (`lexN`, each scope's own max
88
- * → ~1.0) — gating on THAT would make the 0.25×global-best participation gate
89
- * vacuous: any scope with even one scoring doc, however weak, normalizes to
90
- * the same ceiling as every other scope and always clears it. So the gate is
91
- * applied here, before normalization, and gated-out scopes never enter the
92
- * walk/blend/fuse pipeline at all — they go straight to `alsoMatched` with
93
- * their best RAW-lex doc.
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
@@ -1 +1 @@
1
- {"version":3,"file":"fuse.d.ts","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;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;8DAC8D;AAC9D,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAQxC;;;;;;;;;;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;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;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EAAE,EAChB,GAAG,EAAE,YAAY,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,YAAY,CAsDd"}
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 best score is far below the global best
15
- * (< {@link PARTICIPATION_RATIO} ×) is probably an incidental word collision,
16
- * not a second home for the query — it is left out of the fused order and
17
- * reported in `alsoMatched` instead, so the output can say "also matched:
18
- * docs/ — narrow with --in docs/" rather than diluting the pack.
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 soft federation on the RAW lexical scores, walk the
111
- * scope's subgraph, blend exactly like the single-scope path (`lexN +
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 MUST run on raw (pre-normalization) lexical scores. `fuseScopes`'s
118
- * own gate compares its input scores, but this function's input to
119
- * `fuseScopes` is already per-scope-normalized (`lexN`, each scope's own max
120
- * → ~1.0) — gating on THAT would make the 0.25×global-best participation gate
121
- * vacuous: any scope with even one scoring doc, however weak, normalizes to
122
- * the same ceiling as every other scope and always clears it. So the gate is
123
- * applied here, before normalization, and gated-out scopes never enter the
124
- * walk/blend/fuse pipeline at all — they go straight to `alsoMatched` with
125
- * their best RAW-lex doc.
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 — cheap, and needed up front to
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
- if (maxLex < gate) {
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
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fuse.js","sourceRoot":"","sources":["../../src/ask/fuse.ts"],"names":[],"mappings":"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"}
@@ -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;CAChB;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,CA0DrB"}
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"}
@@ -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
- const ids = new Set(graph.nodes.map((n) => n.id));
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":"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"}
1
+ {"version":3,"file":"graphrank.js","sourceRoot":"","sources":["../../src/ask/graphrank.ts"],"names":[],"mappings":"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"}
@@ -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,eAAe,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAIvD;AAED,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,CAkBV;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,CAW7E;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,MAAM,CAItF"}
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"}
@@ -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)} — who depends on it:\n${items.join('\n')}${more}`;
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} — ${ptr}`;
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 — read these spans, do not re-open the files:'
91
- : '[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>"`:';
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}%) — this pack ≈ ` +
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. Positive only
152
- // — names the tools, forbids nothing.
153
- const directive = `[graft] This repo is indexed by graft. To find or understand code, reach for graft first — it cites exact file:line and is faster than grep/read:\n` +
154
- ` • graft ask "<task>" --source — the relevant code, inline (skip the file read)\n` +
155
- ` • graft callers <sym> · graft impact <sym> — who/what breaks if it changes\n` +
156
- ` • graft grep "<literal>" — exhaustive search, grouped by enclosing symbol\n` +
157
- ` • graft skeleton <file> · graft map — a file's API · whole-repo orientation\n`;
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":"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"}
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,gBAAgB,CAAC,CAAQ;IACvC,IAAI,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,UAAU,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,UAAU,QAAQ,CAAC,CAAC;IAC3E,IAAI,CAAC,CAAC,KAAK;QAAE,OAAO,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,OAAO,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,KAAmB,EACnB,OAA4B,EAC5B,GAA8B;IAE9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,KAAK,CAAC,EAAE,CAAC;QACpC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,4BAA4B,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;IACzE,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,SAAS,YAAY,KAAK,CAAC,SAAS,QAAQ,CAAC,CAAC,CAAC;IAC/G,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,EAAE,WAAW,IAAI,CAAC,CAAC;IACxC,IAAI,KAAK,GAAG,CAAC;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,EAAE,YAAY,CAAC,CAAC,CAAC;IAE1E,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC9E,IAAI,KAAK,CAAC,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtF,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9B,IAAI,MAAM,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,CAAU,EAAE,QAAgB;IACjD,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;IAC5B,OAAO,IAAI,GAAG,CACZ,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;SACpF,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,CAAU,EAAE,QAAgB;IACxD,MAAM,GAAG,GAAG,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,GAAG,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACzB,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,CAAU,EAAE,QAAgB,EAAE,GAAG,GAAG,CAAC;IACrE,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7B,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;QAC/D,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,KAAK,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,KAAK,CAAC,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,OAAO,4BAA4B,QAAQ,CAAC,QAAQ,CAAC,yBAAyB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;AAC1G,CAAC;AAWD,SAAS,QAAQ,CAAC,KAAa,IAAY,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAE1E;;mFAEmF;AACnF,SAAS,aAAa,CAAC,IAAqB;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC/B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACzE,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,GAAG,EAAE,CAAC;QACxC,IAAI,IAAI;YAAE,CAAC,IAAI,SAAS,IAAI,EAAE,CAAC;QAC/B,IAAI,CAAC,CAAC,IAAI;YAAE,CAAC,IAAI,aAAa,CAAC,CAAC,IAAI,UAAU,CAAC;QAC/C,OAAO,CAAC,CAAC;IACX,CAAC,CAAC,CAAC;IACH,gFAAgF;IAChF,8EAA8E;IAC9E,gFAAgF;IAChF,qEAAqE;IACrE,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACrC,CAAC,CAAC,wEAAwE;QAC1E,CAAC,CAAC,+LAA+L,CAAC;IACpM,OAAO,GAAG,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC3C,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,GAAY,EAAE,GAAG,GAAG,CAAC;IACxD,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC;IACzE,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC/C,OAAO,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,GAAG,GAAG,CAAC;IACnD,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC9B,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAM,CAAC,aAAa,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;IAC7C,OAAO,CACL,GAAG,IAAI,4BAA4B,KAAK,CAAC,cAAc,EAAE,KAAK,GAAG,kBAAkB;QACnF,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,cAAc,EAAE,uBAAuB,GAAG,CAAC,KAAM,CAAC,KAAK,mBAAmB;QACnG,GAAG,IAAI,CAAC,cAAc,EAAE,kBAAkB,CAC3C,CAAC;AACJ,CAAC;AAED;;;;;+EAK+E;AAC/E,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAExC,kFAAkF;AAClF,MAAM,qBAAqB,GAAG,EAAE,CAAC;AAEjC;;;;;;iEAMiE;AACjE,MAAM,UAAU,iBAAiB,CAAC,GAAY,EAAE,CAAe,EAAE,GAAG,GAAG,CAAC;IACtE,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,GAAG,CAAC,QAAQ,GAAG,mBAAmB;QAAE,OAAO,IAAI,CAAC;IACxF,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3D,IAAI,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC/B,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC;IAC1D,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IACtB,CAAC,CAAC,gBAAgB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,gBAAgB,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;SAC/F,KAAK,CAAC,CAAC,qBAAqB,CAAC,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,WAAW,GAAG,IAAI;IACnE,6EAA6E;IAC7E,4EAA4E;IAC5E,2EAA2E;IAC3E,iFAAiF;IACjF,0EAA0E;IAC1E,mBAAmB;IACnB,MAAM,SAAS,GACb,+YAA+Y;QAC/Y,mNAAmN;QACnN,sKAAsK;QACtK,6HAA6H;QAC7H,sMAAsM;QACtM,iKAAiK;QACjK,iHAAiH;QACjH,wMAAwM,CAAC;IAC3M,OAAO,GAAG,SAAS,iCAAiC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC;AACtF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,OAA4B;IAC5E,MAAM,CAAC,GAAG,OAAO,EAAE,aAAa,EAAE,CAAC,SAAS,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC3D,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;AACpD,CAAC"}
@@ -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":"AAuBA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG7D;AAgDD,wBAAsB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCvD"}
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"}
@@ -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
- const out = execFileSync(process.execPath, [graftCliPath(), ...args], { cwd: dir, encoding: 'utf8', timeout: 8000, stdio: ['ignore', 'pipe', 'ignore'] });
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 ask = graftJson(dir, ['ask', prompt, '.', '--json', '-n', '3']);
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';