@nanonets/graft 0.8.0 → 0.8.2

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 (108) hide show
  1. package/README.md +45 -15
  2. package/dist/ask/ask.js +1 -1
  3. package/dist/ask/ask.js.map +1 -1
  4. package/dist/claude/format.d.ts +40 -13
  5. package/dist/claude/format.d.ts.map +1 -1
  6. package/dist/claude/format.js +54 -15
  7. package/dist/claude/format.js.map +1 -1
  8. package/dist/claude/hooks.d.ts +15 -0
  9. package/dist/claude/hooks.d.ts.map +1 -1
  10. package/dist/claude/hooks.js +52 -3
  11. package/dist/claude/hooks.js.map +1 -1
  12. package/dist/claude/init.d.ts +17 -0
  13. package/dist/claude/init.d.ts.map +1 -1
  14. package/dist/claude/init.js +47 -21
  15. package/dist/claude/init.js.map +1 -1
  16. package/dist/claude/settings-merge.d.ts.map +1 -1
  17. package/dist/claude/settings-merge.js +19 -2
  18. package/dist/claude/settings-merge.js.map +1 -1
  19. package/dist/claude/skill-template.d.ts.map +1 -1
  20. package/dist/claude/skill-template.js +13 -5
  21. package/dist/claude/skill-template.js.map +1 -1
  22. package/dist/claude/state.d.ts +5 -20
  23. package/dist/claude/state.d.ts.map +1 -1
  24. package/dist/claude/state.js +10 -73
  25. package/dist/claude/state.js.map +1 -1
  26. package/dist/cli-picker.d.ts +60 -0
  27. package/dist/cli-picker.d.ts.map +1 -0
  28. package/dist/cli-picker.js +268 -0
  29. package/dist/cli-picker.js.map +1 -0
  30. package/dist/cli.js +101 -12
  31. package/dist/cli.js.map +1 -1
  32. package/dist/context/node-file.d.ts +21 -0
  33. package/dist/context/node-file.d.ts.map +1 -1
  34. package/dist/context/node-file.js +63 -1
  35. package/dist/context/node-file.js.map +1 -1
  36. package/dist/engine.d.ts +2 -0
  37. package/dist/engine.d.ts.map +1 -1
  38. package/dist/engine.js +1 -0
  39. package/dist/engine.js.map +1 -1
  40. package/dist/graph/build.d.ts +13 -2
  41. package/dist/graph/build.d.ts.map +1 -1
  42. package/dist/graph/build.js +98 -20
  43. package/dist/graph/build.js.map +1 -1
  44. package/dist/graph/cards.d.ts.map +1 -1
  45. package/dist/graph/cards.js +8 -0
  46. package/dist/graph/cards.js.map +1 -1
  47. package/dist/graph/extract-cache.d.ts +96 -0
  48. package/dist/graph/extract-cache.d.ts.map +1 -0
  49. package/dist/graph/extract-cache.js +199 -0
  50. package/dist/graph/extract-cache.js.map +1 -0
  51. package/dist/graph/fingerprint.d.ts +70 -0
  52. package/dist/graph/fingerprint.d.ts.map +1 -0
  53. package/dist/graph/fingerprint.js +147 -0
  54. package/dist/graph/fingerprint.js.map +1 -0
  55. package/dist/graph/load.d.ts +11 -0
  56. package/dist/graph/load.d.ts.map +1 -1
  57. package/dist/graph/load.js +14 -0
  58. package/dist/graph/load.js.map +1 -1
  59. package/dist/graph/refresh.d.ts +49 -0
  60. package/dist/graph/refresh.d.ts.map +1 -0
  61. package/dist/graph/refresh.js +202 -0
  62. package/dist/graph/refresh.js.map +1 -0
  63. package/dist/graph/source-files.d.ts +18 -0
  64. package/dist/graph/source-files.d.ts.map +1 -0
  65. package/dist/graph/source-files.js +36 -0
  66. package/dist/graph/source-files.js.map +1 -0
  67. package/dist/graph/traverse-cli.d.ts +1 -1
  68. package/dist/graph/traverse-cli.js +2 -2
  69. package/dist/graph/traverse.d.ts +2 -2
  70. package/dist/graph/traverse.js +1 -1
  71. package/dist/hosts/codex-hooks.d.ts +8 -0
  72. package/dist/hosts/codex-hooks.d.ts.map +1 -1
  73. package/dist/hosts/codex-hooks.js +27 -4
  74. package/dist/hosts/codex-hooks.js.map +1 -1
  75. package/dist/hosts/init.d.ts +2 -0
  76. package/dist/hosts/init.d.ts.map +1 -1
  77. package/dist/hosts/init.js +5 -2
  78. package/dist/hosts/init.js.map +1 -1
  79. package/dist/hosts/mcp-config.d.ts +29 -1
  80. package/dist/hosts/mcp-config.d.ts.map +1 -1
  81. package/dist/hosts/mcp-config.js +77 -10
  82. package/dist/hosts/mcp-config.js.map +1 -1
  83. package/dist/hosts/plan.d.ts +32 -0
  84. package/dist/hosts/plan.d.ts.map +1 -0
  85. package/dist/hosts/plan.js +67 -0
  86. package/dist/hosts/plan.js.map +1 -0
  87. package/dist/hosts/registry.d.ts.map +1 -1
  88. package/dist/hosts/registry.js +9 -0
  89. package/dist/hosts/registry.js.map +1 -1
  90. package/dist/mcp/instructions.d.ts +29 -0
  91. package/dist/mcp/instructions.d.ts.map +1 -0
  92. package/dist/mcp/instructions.js +55 -0
  93. package/dist/mcp/instructions.js.map +1 -0
  94. package/dist/mcp/server.d.ts +6 -1
  95. package/dist/mcp/server.d.ts.map +1 -1
  96. package/dist/mcp/server.js +15 -4
  97. package/dist/mcp/server.js.map +1 -1
  98. package/dist/mcp/tools.d.ts +4 -2
  99. package/dist/mcp/tools.d.ts.map +1 -1
  100. package/dist/mcp/tools.js +144 -104
  101. package/dist/mcp/tools.js.map +1 -1
  102. package/dist/search/grep-cli.js +1 -1
  103. package/dist/search/grep.js +1 -1
  104. package/dist/util/state.d.ts +45 -0
  105. package/dist/util/state.d.ts.map +1 -0
  106. package/dist/util/state.js +121 -0
  107. package/dist/util/state.js.map +1 -0
  108. package/package.json +1 -1
@@ -0,0 +1,96 @@
1
+ import type { RawEdge } from "./extract.js";
2
+ import type { NodeV1 } from "./types.js";
3
+ export interface ExtractEntry {
4
+ size: number;
5
+ mtimeMs: number;
6
+ /** sha256 of the file's bytes — the same value as its `kind:"file"` node's `body_hash`. */
7
+ hash: string;
8
+ nodes: NodeV1[];
9
+ rawEdges: RawEdge[];
10
+ /** Set when this file couldn't be read or parsed. The entry exists anyway so the
11
+ * freshness probe doesn't flag the file as new on every query; replaying it
12
+ * re-reports the same error and contributes no nodes, exactly as a cold build
13
+ * would. */
14
+ error?: string;
15
+ }
16
+ export interface ExtractCache {
17
+ version: number;
18
+ /** Identity of the extractor that produced these entries. */
19
+ extractor: string;
20
+ /** repo-relative source path → its last parse. */
21
+ files: Record<string, ExtractEntry>;
22
+ }
23
+ /**
24
+ * Where this graft's memo lives: `<outDir>/.cache/extract.<stamp>.json`.
25
+ *
26
+ * The stamp is in the *filename*, not just inside the file, so two grafts working
27
+ * on one repo keep separate memos instead of evicting each other. That is the
28
+ * default install, not an exotic case: `graft init` wires the MCP server as
29
+ * `npx -y @nanonets/graft` (which resolves the latest published version) while the
30
+ * Claude Code hooks run the locally installed one. The moment those two versions
31
+ * differ, a single shared file means the prompt hook and every MCP retrieval take
32
+ * turns rejecting each other's entries and cold-re-parsing the whole repo — the memo
33
+ * would never help anyone.
34
+ *
35
+ * Null stamp → null path → no memo at all. See {@link extractorStamp}.
36
+ */
37
+ export declare function extractCachePath(outDir: string): string | null;
38
+ /** Keep `.cache/` from growing a file per version forever: after writing, drop all
39
+ * but the newest `keep` files sharing a prefix. Best-effort and never fatal — this
40
+ * is a cache directory, and a failure here costs disk, not correctness. */
41
+ export declare function pruneSidecars(cacheDir: string, prefix: string, keep?: number): void;
42
+ /**
43
+ * Identity of the code that produces the cached parses. Both sidecars key on it,
44
+ * so *anything* that can change extraction output has to change this string.
45
+ *
46
+ * Content-hashed over every sibling module in this directory, plus the package
47
+ * version. Two earlier instincts are deliberately rejected:
48
+ *
49
+ * - **Not a timestamp.** This was `mtime:size` of `extract.js` alone, which is
50
+ * wrong in both directions. Too loose: the parse of `db.count()` depends on
51
+ * `bindings.ts` deciding that `db` is a `UserRepo` (that answer is stored *in*
52
+ * the cached entry, as an edge's `recvType`), and fixing a binding bug leaves
53
+ * `extract.js`'s emitted bytes untouched — so any build that skips rewriting
54
+ * unchanged output keeps the old stamp and silently replays pre-fix edges. Too
55
+ * tight: a rebuild that rewrites identical content moves the mtime and throws
56
+ * away the whole memo for nothing.
57
+ * - **Not a hand-kept list of modules.** A list is correct exactly until someone
58
+ * moves parse logic into a module nobody added to it, and the failure is silent.
59
+ *
60
+ * Hashing the directory over-invalidates a little — editing any `graph/` module
61
+ * costs one cold rebuild — which is no more often than a version bump already
62
+ * costs, and always in the safe direction. The package version is folded in so a
63
+ * tree-sitter grammar upgrade (which changes parse output without changing any of
64
+ * graft's own files) invalidates too.
65
+ *
66
+ * Measured at ~0.5ms for 21 files / 556KB, paid once per process.
67
+ *
68
+ * **Null when no identity can be established at all**, and that is deliberately not
69
+ * a string. It used to return `"unknown"` on failure — but `"unknown"` was then
70
+ * *written into the sidecars as a real identity*, and every later run compared equal
71
+ * to it, so any environment where stamping fails (a `pkg`/`bun-compile` single-file
72
+ * build, an asar-style read, a directory that can't be listed) permanently lost the
73
+ * ability to notice an extractor change. A sentinel that doubles as a valid value
74
+ * silently disables the whole mechanism. Null forces callers to decide instead, and
75
+ * {@link extractCachePath} decides not to have a memo.
76
+ */
77
+ export declare function extractorStamp(): string | null;
78
+ /**
79
+ * Hash every `ext` file in `dir`, plus `version`. Null when the directory holds no
80
+ * such file. Separated from {@link extractorStamp} so a test can prove the property
81
+ * that matters: a change to *any* module in the directory moves the stamp, not just
82
+ * the one the old implementation happened to watch.
83
+ */
84
+ export declare function stampDir(dir: string, ext: string, version?: string): string | null;
85
+ export declare function emptyExtractCache(): ExtractCache;
86
+ /** The cache for `outDir`, or an empty one when it's absent, unparseable, written by
87
+ * a different cache version, or when this graft has no identity to key on (then
88
+ * every build is cold, which is slow but never wrong). The stamp is in the filename,
89
+ * so the `extractor` field is a second check rather than the only one. */
90
+ export declare function readExtractCache(outDir: string): ExtractCache;
91
+ /** Best-effort write — a full graph is already on disk by the time this runs, so an
92
+ * unwritable cache dir must never fail the build (it only costs the next build its
93
+ * reuse). Returns false when nothing was written, including the deliberate case of
94
+ * having no extractor identity: a parse we can't attribute must never be replayed. */
95
+ export declare function writeExtractCache(outDir: string, cache: ExtractCache): boolean;
96
+ //# sourceMappingURL=extract-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-cache.d.ts","sourceRoot":"","sources":["../../src/graph/extract-cache.ts"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAMzC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB;;;gBAGY;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG9D;AAED;;2EAE2E;AAC3E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,IAAI,CAa9E;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,cAAc,IAAI,MAAM,GAAG,IAAI,CAG9C;AAoBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,SAAK,GAAG,MAAM,GAAG,IAAI,CAU9E;AAYD,wBAAgB,iBAAiB,IAAI,YAAY,CAEhD;AAED;;;0EAG0E;AAC1E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAS7D;AAED;;;sFAGsF;AACtF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAU9E"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Per-file memo for Tier-1 extraction — `<outDir>/.cache/extract.json`.
3
+ *
4
+ * `extractFile` is pure and file-local (`rel`, `source`, `lang` → `{nodes,
5
+ * rawEdges}`), which is the whole trick: an unchanged file's parse result can be
6
+ * replayed from disk instead of re-running tree-sitter. That turns
7
+ * {@link buildGraph} from "always re-parse the repo" (~4.6ms/file) into "re-parse
8
+ * only what moved", which is what makes a rebuild cheap enough to run *before*
9
+ * every query (see `graph/refresh.ts`).
10
+ *
11
+ * Everything downstream of extraction (edge resolution, enrichment, the graph
12
+ * write, the ask sidecar, cards) still runs over the whole merged node set, so no
13
+ * other invariant changes — an incremental build must produce a byte-identical
14
+ * `wiring.json` to a cold one.
15
+ *
16
+ * Crucially the cached nodes keep `body_text`: `writeGraph` strips it before
17
+ * serializing, so `wiring.json` can never be the reuse source — the ask sidecar
18
+ * needs a body for every node, including the ones we didn't re-parse.
19
+ *
20
+ * Lives under `.cache/` (gitignored, regenerate-anytime) next to `ask-index.json`
21
+ * and `summaries.json`. Two things invalidate the whole file: a bump of
22
+ * {@link CACHE_VERSION} for a change of on-disk shape, and a change to the
23
+ * extraction code itself, caught by content-hashing it — see
24
+ * {@link extractorStamp}. Neither asks anyone to remember to bump anything.
25
+ */
26
+ import { readFileSync, readdirSync, rmSync, statSync } from "node:fs";
27
+ import { createHash } from "node:crypto";
28
+ import { fileURLToPath } from "node:url";
29
+ import { dirname, extname, join } from "node:path";
30
+ import { CACHE_DIR } from "../context/node-file.js";
31
+ import { readJson, writeJsonAtomic } from "../util/state.js";
32
+ /** Bump when the on-disk shape below changes. */
33
+ const CACHE_VERSION = 1;
34
+ const EXTRACT_CACHE_PREFIX = "extract";
35
+ /**
36
+ * Where this graft's memo lives: `<outDir>/.cache/extract.<stamp>.json`.
37
+ *
38
+ * The stamp is in the *filename*, not just inside the file, so two grafts working
39
+ * on one repo keep separate memos instead of evicting each other. That is the
40
+ * default install, not an exotic case: `graft init` wires the MCP server as
41
+ * `npx -y @nanonets/graft` (which resolves the latest published version) while the
42
+ * Claude Code hooks run the locally installed one. The moment those two versions
43
+ * differ, a single shared file means the prompt hook and every MCP retrieval take
44
+ * turns rejecting each other's entries and cold-re-parsing the whole repo — the memo
45
+ * would never help anyone.
46
+ *
47
+ * Null stamp → null path → no memo at all. See {@link extractorStamp}.
48
+ */
49
+ export function extractCachePath(outDir) {
50
+ const stamp = extractorStamp();
51
+ return stamp === null ? null : join(outDir, CACHE_DIR, `${EXTRACT_CACHE_PREFIX}.${stamp}.json`);
52
+ }
53
+ /** Keep `.cache/` from growing a file per version forever: after writing, drop all
54
+ * but the newest `keep` files sharing a prefix. Best-effort and never fatal — this
55
+ * is a cache directory, and a failure here costs disk, not correctness. */
56
+ export function pruneSidecars(cacheDir, prefix, keep = 2) {
57
+ try {
58
+ const mine = readdirSync(cacheDir)
59
+ .filter((f) => f.startsWith(`${prefix}.`) && f.endsWith(".json"))
60
+ .map((f) => {
61
+ const full = join(cacheDir, f);
62
+ return { full, mtimeMs: statSync(full).mtimeMs };
63
+ })
64
+ .sort((a, b) => b.mtimeMs - a.mtimeMs);
65
+ for (const f of mine.slice(keep))
66
+ rmSync(f.full, { force: true });
67
+ }
68
+ catch {
69
+ /* nothing here is load-bearing */
70
+ }
71
+ }
72
+ /** Computed once per process — this can't change under a running process without
73
+ * the module graph itself being swapped, and a long-lived MCP server holding the
74
+ * identity of the code it actually loaded is the correct answer anyway.
75
+ * `undefined` = not computed yet; `null` = computed, and there is no identity. */
76
+ let memoizedStamp;
77
+ /**
78
+ * Identity of the code that produces the cached parses. Both sidecars key on it,
79
+ * so *anything* that can change extraction output has to change this string.
80
+ *
81
+ * Content-hashed over every sibling module in this directory, plus the package
82
+ * version. Two earlier instincts are deliberately rejected:
83
+ *
84
+ * - **Not a timestamp.** This was `mtime:size` of `extract.js` alone, which is
85
+ * wrong in both directions. Too loose: the parse of `db.count()` depends on
86
+ * `bindings.ts` deciding that `db` is a `UserRepo` (that answer is stored *in*
87
+ * the cached entry, as an edge's `recvType`), and fixing a binding bug leaves
88
+ * `extract.js`'s emitted bytes untouched — so any build that skips rewriting
89
+ * unchanged output keeps the old stamp and silently replays pre-fix edges. Too
90
+ * tight: a rebuild that rewrites identical content moves the mtime and throws
91
+ * away the whole memo for nothing.
92
+ * - **Not a hand-kept list of modules.** A list is correct exactly until someone
93
+ * moves parse logic into a module nobody added to it, and the failure is silent.
94
+ *
95
+ * Hashing the directory over-invalidates a little — editing any `graph/` module
96
+ * costs one cold rebuild — which is no more often than a version bump already
97
+ * costs, and always in the safe direction. The package version is folded in so a
98
+ * tree-sitter grammar upgrade (which changes parse output without changing any of
99
+ * graft's own files) invalidates too.
100
+ *
101
+ * Measured at ~0.5ms for 21 files / 556KB, paid once per process.
102
+ *
103
+ * **Null when no identity can be established at all**, and that is deliberately not
104
+ * a string. It used to return `"unknown"` on failure — but `"unknown"` was then
105
+ * *written into the sidecars as a real identity*, and every later run compared equal
106
+ * to it, so any environment where stamping fails (a `pkg`/`bun-compile` single-file
107
+ * build, an asar-style read, a directory that can't be listed) permanently lost the
108
+ * ability to notice an extractor change. A sentinel that doubles as a valid value
109
+ * silently disables the whole mechanism. Null forces callers to decide instead, and
110
+ * {@link extractCachePath} decides not to have a memo.
111
+ */
112
+ export function extractorStamp() {
113
+ if (memoizedStamp === undefined)
114
+ memoizedStamp = computeStamp();
115
+ return memoizedStamp;
116
+ }
117
+ function computeStamp() {
118
+ try {
119
+ const self = fileURLToPath(import.meta.url);
120
+ // `.js` when running from `dist/`, `.ts` under tsx — take the extension from
121
+ // our own filename rather than guessing which layout we're in.
122
+ const dir = dirname(self);
123
+ const hashed = stampDir(dir, extname(self), packageVersion(dir) ?? "");
124
+ if (hashed)
125
+ return hashed;
126
+ // Couldn't read the modules (bundled into one file, say). The version alone is
127
+ // a weaker identity — it can't see a local edit — but it still turns over on
128
+ // every upgrade, which is the case that ships broken parses to users.
129
+ const v = packageVersion(dir);
130
+ return v ? `v${v}` : null;
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ }
136
+ /**
137
+ * Hash every `ext` file in `dir`, plus `version`. Null when the directory holds no
138
+ * such file. Separated from {@link extractorStamp} so a test can prove the property
139
+ * that matters: a change to *any* module in the directory moves the stamp, not just
140
+ * the one the old implementation happened to watch.
141
+ */
142
+ export function stampDir(dir, ext, version = "") {
143
+ const files = readdirSync(dir).filter((f) => f.endsWith(ext)).sort();
144
+ if (!files.length)
145
+ return null;
146
+ const h = createHash("sha256");
147
+ h.update(version);
148
+ for (const f of files) {
149
+ h.update(f); // a rename is a change, even at identical content
150
+ h.update(readFileSync(join(dir, f)));
151
+ }
152
+ return h.digest("hex").slice(0, 16);
153
+ }
154
+ /** graft's own version, or null when it can't be read. */
155
+ function packageVersion(graphDir) {
156
+ try {
157
+ const pkg = JSON.parse(readFileSync(join(graphDir, "..", "..", "package.json"), "utf8"));
158
+ return pkg.version ?? null;
159
+ }
160
+ catch {
161
+ return null;
162
+ }
163
+ }
164
+ export function emptyExtractCache() {
165
+ return { version: CACHE_VERSION, extractor: extractorStamp() ?? "", files: {} };
166
+ }
167
+ /** The cache for `outDir`, or an empty one when it's absent, unparseable, written by
168
+ * a different cache version, or when this graft has no identity to key on (then
169
+ * every build is cold, which is slow but never wrong). The stamp is in the filename,
170
+ * so the `extractor` field is a second check rather than the only one. */
171
+ export function readExtractCache(outDir) {
172
+ const path = extractCachePath(outDir);
173
+ const stamp = extractorStamp();
174
+ if (path === null || stamp === null)
175
+ return emptyExtractCache();
176
+ const c = readJson(path);
177
+ if (!c || c.version !== CACHE_VERSION || c.extractor !== stamp || typeof c.files !== "object") {
178
+ return emptyExtractCache();
179
+ }
180
+ return { version: c.version, extractor: c.extractor, files: c.files ?? {} };
181
+ }
182
+ /** Best-effort write — a full graph is already on disk by the time this runs, so an
183
+ * unwritable cache dir must never fail the build (it only costs the next build its
184
+ * reuse). Returns false when nothing was written, including the deliberate case of
185
+ * having no extractor identity: a parse we can't attribute must never be replayed. */
186
+ export function writeExtractCache(outDir, cache) {
187
+ const path = extractCachePath(outDir);
188
+ if (path === null)
189
+ return false;
190
+ try {
191
+ writeJsonAtomic(path, cache, true);
192
+ pruneSidecars(join(outDir, CACHE_DIR), EXTRACT_CACHE_PREFIX);
193
+ return true;
194
+ }
195
+ catch {
196
+ return false;
197
+ }
198
+ }
199
+ //# sourceMappingURL=extract-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-cache.js","sourceRoot":"","sources":["../../src/graph/extract-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import { type ExtractEntry } from "./extract-cache.js";
2
+ /** `[size, mtimeMs, hash]` — positional to keep the file small. */
3
+ type Print = [number, number, string];
4
+ export interface Fingerprint {
5
+ version: number;
6
+ /** The extractor that produced the graph these prints describe — the same stamp
7
+ * `extract.json` carries. Without it the two sidecars can disagree about whether
8
+ * the graph is current: an extractor change correctly drops every memo entry,
9
+ * yet the prints still match the tree byte-for-byte, so the probe would report
10
+ * clean and queries would keep answering from nodes the old extractor built. */
11
+ extractor: string;
12
+ files: Record<string, Print>;
13
+ }
14
+ /** What moved since the last build. Empty in all three arrays = nothing to do. */
15
+ export interface Drift {
16
+ /** Recorded files whose bytes differ now. */
17
+ changed: string[];
18
+ /** Source files with no record — new, or never indexed. */
19
+ added: string[];
20
+ /** Recorded files that are gone from disk. */
21
+ removed: string[];
22
+ }
23
+ /** `<outDir>/.cache/fingerprint.<stamp>.json` — keyed by extractor identity for the
24
+ * same reason the memo is (see {@link extractCachePath}): two grafts on one repo,
25
+ * typically an `npx` MCP server and a locally installed hook binary, must not keep
26
+ * invalidating each other's prints and forcing a cold rebuild on every call. */
27
+ export declare function fingerprintPath(outDir: string): string;
28
+ export declare function readFingerprint(outDir: string): Fingerprint | null;
29
+ /** Project the extraction cache's entries into the probe sidecar. Best-effort:
30
+ * the graph is already on disk when this runs, so a failed write costs the next
31
+ * probe its fast path and nothing more. */
32
+ export declare function writeFingerprint(outDir: string, entries: Record<string, ExtractEntry>): boolean;
33
+ /** `GRAFT_REFRESH=hash` — never trust a stat, confirm every file by its bytes. */
34
+ export declare function alwaysHash(): boolean;
35
+ /**
36
+ * May a recorded `(size, mtimeMs, hash)` be trusted for the file `f` as it is on
37
+ * disk now, without reading it?
38
+ *
39
+ * **The probe's rule only.** `buildGraph` deliberately does not use this: it reads
40
+ * and hashes every file, every time. A stat may decide whether a query bothers
41
+ * rebuilding; it may not decide what the rebuild itself looks at — otherwise
42
+ * `graft check` (which always re-hashes) can report drift that the `graft build` it
43
+ * recommends then refuses to repair. `GRAFT_REFRESH=hash` is the escape hatch for
44
+ * the probe's blind spot: a same-length edit inside one mtime tick.
45
+ *
46
+ * An empty `hash` means the last build never got the bytes — always re-read.
47
+ * A *parse* failure keeps its real hash, so it stays on the fast path: re-reading
48
+ * bytes that failed to parse yesterday just fails to parse again.
49
+ */
50
+ export declare function statUnchanged(rec: {
51
+ size: number;
52
+ mtimeMs: number;
53
+ hash: string;
54
+ }, f: {
55
+ size: number;
56
+ mtimeMs: number;
57
+ }): boolean;
58
+ export declare function isClean(d: Drift): boolean;
59
+ export declare function driftCount(d: Drift): number;
60
+ /**
61
+ * Diff the working tree against the last build's fingerprint. Returns null when
62
+ * there is no fingerprint to compare against (never built, or built by a version
63
+ * that didn't write one) — callers should treat that as "unknown", not "clean".
64
+ *
65
+ * `GRAFT_REFRESH=hash` skips the stat fast path and hashes every file, for the
66
+ * rare tooling that rewrites content while preserving size and mtime.
67
+ */
68
+ export declare function probeDrift(root: string, outDir: string): Drift | null;
69
+ export {};
70
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/graph/fingerprint.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAiC,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AActF,mEAAmE;AACnE,KAAK,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB;;;;oFAIgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;CAC9B;AAED,kFAAkF;AAClF,MAAM,WAAW,KAAK;IACpB,6CAA6C;IAC7C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;gFAGgF;AAChF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAKlE;AAED;;2CAE2C;AAC3C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,OAAO,CAU/F;AAED,kFAAkF;AAClF,wBAAgB,UAAU,IAAI,OAAO,CAEpC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EACpD,CAAC,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC,OAAO,CAIT;AAED,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAEzC;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAE3C;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAqCrE"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * The cheap "has the working tree moved?" probe that gates the pre-query rebuild.
3
+ *
4
+ * Every graft retrieval call runs this, so it has to be ~free on the common
5
+ * unchanged path: a walk + one `stat` per source file, no reads, no parsing.
6
+ * Measured at ~3ms for 280 files. Only files whose `(size, mtimeMs)` disagree
7
+ * with the last build's record get read and hashed, which is what keeps a `touch`
8
+ * or a `git checkout` of identical bytes from triggering a pointless rebuild.
9
+ *
10
+ * Note graft has no notion of git here (it never shells out to git, never reads
11
+ * `.git`): drift is measured against the bytes in the working tree, so an
12
+ * uncommitted, staged, or committed edit all look the same — which is the point.
13
+ *
14
+ * `<outDir>/.cache/fingerprint.json` is a projection of the extraction cache
15
+ * (`extract-cache.ts`) minus the parse results, written by the same build. Keeping
16
+ * it separate means the probe reads ~10KB instead of the multi-MB parse cache. The
17
+ * two can only ever disagree by one sidecar going missing, and both directions
18
+ * degrade safely: no fingerprint → "unknown, rebuild"; no parse cache → the
19
+ * rebuild is just cold.
20
+ */
21
+ import { readFileSync } from "node:fs";
22
+ import { join } from "node:path";
23
+ import { CACHE_DIR } from "../context/node-file.js";
24
+ import { contentHash } from "../util/id.js";
25
+ import { readJson, writeJsonAtomic } from "../util/state.js";
26
+ import { extractorStamp, pruneSidecars } from "./extract-cache.js";
27
+ import { listSourceStats } from "./source-files.js";
28
+ const FINGERPRINT_PREFIX = "fingerprint";
29
+ const FINGERPRINT_VERSION = 1;
30
+ /** The identity this graft's prints are filed under. Unlike the extract memo, a
31
+ * missing extractor identity is *not* disqualifying here: freshness is a claim about
32
+ * source bytes, and a build with no memo is merely cold, never wrong. So stamp what
33
+ * we can and fall back to a shared bucket. */
34
+ function stamp() {
35
+ return extractorStamp() ?? "nostamp";
36
+ }
37
+ /** `<outDir>/.cache/fingerprint.<stamp>.json` — keyed by extractor identity for the
38
+ * same reason the memo is (see {@link extractCachePath}): two grafts on one repo,
39
+ * typically an `npx` MCP server and a locally installed hook binary, must not keep
40
+ * invalidating each other's prints and forcing a cold rebuild on every call. */
41
+ export function fingerprintPath(outDir) {
42
+ return join(outDir, CACHE_DIR, `${FINGERPRINT_PREFIX}.${stamp()}.json`);
43
+ }
44
+ export function readFingerprint(outDir) {
45
+ const f = readJson(fingerprintPath(outDir));
46
+ if (!f || f.version !== FINGERPRINT_VERSION || typeof f.files !== "object" || !f.files)
47
+ return null;
48
+ if (f.extractor !== stamp())
49
+ return null; // different extractor — re-extract, don't trust these prints
50
+ return f;
51
+ }
52
+ /** Project the extraction cache's entries into the probe sidecar. Best-effort:
53
+ * the graph is already on disk when this runs, so a failed write costs the next
54
+ * probe its fast path and nothing more. */
55
+ export function writeFingerprint(outDir, entries) {
56
+ const files = {};
57
+ for (const [rel, e] of Object.entries(entries))
58
+ files[rel] = [e.size, e.mtimeMs, e.hash];
59
+ try {
60
+ writeJsonAtomic(fingerprintPath(outDir), { version: FINGERPRINT_VERSION, extractor: stamp(), files }, true);
61
+ pruneSidecars(join(outDir, CACHE_DIR), FINGERPRINT_PREFIX);
62
+ return true;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ /** `GRAFT_REFRESH=hash` — never trust a stat, confirm every file by its bytes. */
69
+ export function alwaysHash() {
70
+ return process.env.GRAFT_REFRESH === "hash";
71
+ }
72
+ /**
73
+ * May a recorded `(size, mtimeMs, hash)` be trusted for the file `f` as it is on
74
+ * disk now, without reading it?
75
+ *
76
+ * **The probe's rule only.** `buildGraph` deliberately does not use this: it reads
77
+ * and hashes every file, every time. A stat may decide whether a query bothers
78
+ * rebuilding; it may not decide what the rebuild itself looks at — otherwise
79
+ * `graft check` (which always re-hashes) can report drift that the `graft build` it
80
+ * recommends then refuses to repair. `GRAFT_REFRESH=hash` is the escape hatch for
81
+ * the probe's blind spot: a same-length edit inside one mtime tick.
82
+ *
83
+ * An empty `hash` means the last build never got the bytes — always re-read.
84
+ * A *parse* failure keeps its real hash, so it stays on the fast path: re-reading
85
+ * bytes that failed to parse yesterday just fails to parse again.
86
+ */
87
+ export function statUnchanged(rec, f) {
88
+ if (alwaysHash())
89
+ return false;
90
+ if (!rec.hash)
91
+ return false;
92
+ return rec.size === f.size && rec.mtimeMs === f.mtimeMs;
93
+ }
94
+ export function isClean(d) {
95
+ return d.changed.length === 0 && d.added.length === 0 && d.removed.length === 0;
96
+ }
97
+ export function driftCount(d) {
98
+ return d.changed.length + d.added.length + d.removed.length;
99
+ }
100
+ /**
101
+ * Diff the working tree against the last build's fingerprint. Returns null when
102
+ * there is no fingerprint to compare against (never built, or built by a version
103
+ * that didn't write one) — callers should treat that as "unknown", not "clean".
104
+ *
105
+ * `GRAFT_REFRESH=hash` skips the stat fast path and hashes every file, for the
106
+ * rare tooling that rewrites content while preserving size and mtime.
107
+ */
108
+ export function probeDrift(root, outDir) {
109
+ const fp = readFingerprint(outDir);
110
+ if (!fp)
111
+ return null;
112
+ const drift = { changed: [], added: [], removed: [] };
113
+ const seen = new Set();
114
+ for (const f of listSourceStats(root, outDir)) {
115
+ seen.add(f.rel);
116
+ const print = fp.files[f.rel];
117
+ if (!print) {
118
+ drift.added.push(f.rel);
119
+ continue;
120
+ }
121
+ const [size, mtimeMs, hash] = print;
122
+ if (statUnchanged({ size, mtimeMs, hash }, f))
123
+ continue;
124
+ // Suspect: confirm by bytes, so a touch (or a checkout that restores the
125
+ // same content) doesn't cost a rebuild. An entry with an empty hash lands
126
+ // here every time by design — that's a file the last build couldn't read, and
127
+ // the only way to learn it's readable again is to try.
128
+ let now;
129
+ try {
130
+ now = contentHash(readFileSync(f.abs, "utf8"));
131
+ }
132
+ catch {
133
+ continue; // unreadable right now — leave it to the next probe
134
+ }
135
+ if (now !== hash)
136
+ drift.changed.push(f.rel);
137
+ }
138
+ for (const rel of Object.keys(fp.files)) {
139
+ if (!seen.has(rel))
140
+ drift.removed.push(rel);
141
+ }
142
+ drift.changed.sort();
143
+ drift.added.sort();
144
+ drift.removed.sort();
145
+ return drift;
146
+ }
147
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/graph/fingerprint.ts"],"names":[],"mappings":"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"}
@@ -15,4 +15,15 @@ export declare function loadGraphCached(outDir: string): GraphV1 | null;
15
15
  /** Cached `readAskIndex(outDir)` — same semantics, keyed on the sidecar file.
16
16
  * Returns a shared cached reference; callers must not mutate the returned index. */
17
17
  export declare function loadAskIndexCached(outDir: string): AskIndex | null;
18
+ /**
19
+ * Drop the cached graph + sidecar for `outDir`, forcing the next load to re-read.
20
+ *
21
+ * The `(mtimeMs, size)` key above is a good invalidator for a build that happened
22
+ * in *another* process, but not for one this process just performed: the
23
+ * pre-query auto-refresh (`refresh.ts`) rewrites the graph and then immediately
24
+ * queries it, and on a filesystem with coarse mtime resolution a same-tick rewrite
25
+ * of the same size would be served from the stale entry. Callers that rebuild must
26
+ * therefore invalidate explicitly rather than trust the clock.
27
+ */
28
+ export declare function invalidateGraphCaches(outDir: string): void;
18
29
  //# sourceMappingURL=load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/graph/load.ts"],"names":[],"mappings":"AA2BA,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAW1C;6EAC6E;AAC7E,eAAO,MAAM,YAAY;;;CAA4B,CAAC;AAEtD,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AAmCD;;oFAEoF;AACpF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAK9D;AAED;oFACoF;AACpF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAKlE"}
1
+ {"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/graph/load.ts"],"names":[],"mappings":"AA2BA,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AACjF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAW1C;6EAC6E;AAC7E,eAAO,MAAM,YAAY;;;CAA4B,CAAC;AAEtD,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC;AAmCD;;oFAEoF;AACpF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAK9D;AAED;oFACoF;AACpF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAKlE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAG1D"}
@@ -80,4 +80,18 @@ export function loadAskIndexCached(outDir) {
80
80
  __parseCount.askIndex++;
81
81
  });
82
82
  }
83
+ /**
84
+ * Drop the cached graph + sidecar for `outDir`, forcing the next load to re-read.
85
+ *
86
+ * The `(mtimeMs, size)` key above is a good invalidator for a build that happened
87
+ * in *another* process, but not for one this process just performed: the
88
+ * pre-query auto-refresh (`refresh.ts`) rewrites the graph and then immediately
89
+ * queries it, and on a filesystem with coarse mtime resolution a same-tick rewrite
90
+ * of the same size would be served from the stale entry. Callers that rebuild must
91
+ * therefore invalidate explicitly rather than trust the clock.
92
+ */
93
+ export function invalidateGraphCaches(outDir) {
94
+ graphCache.delete(wiringPath(outDir));
95
+ askIndexCache.delete(askIndexPath(outDir));
96
+ }
83
97
  //# sourceMappingURL=load.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/graph/load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAiB,MAAM,sBAAsB,CAAC;AASjF,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+B,CAAC;AAC1D,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgC,CAAC;AAE9D;6EAC6E;AAC7E,MAAM,CAAC,MAAM,YAAY,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAEtD,+EAA+E;AAC/E,MAAM,UAAU,kBAAkB;IAChC,YAAY,CAAC,KAAK,GAAG,CAAC,CAAC;IACvB,YAAY,CAAC,QAAQ,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CACjB,KAAiC,EACjC,IAAY,EACZ,KAAqB,EACrB,OAAmB;IAEnB,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,sEAAsE;QACtE,sEAAsE;QACtE,+CAA+C;QAC/C,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,EAAE,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;QACvE,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,CAAC;IACV,MAAM,KAAK,GAAG,KAAK,EAAE,CAAC;IACtB,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC/D,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;oFAEoF;AACpF,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE;QAC9D,YAAY,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;oFACoF;AACpF,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAClC,OAAO,UAAU,CAAC,aAAa,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE;QACtE,YAAY,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/graph/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ import { type Drift } from "./fingerprint.js";
2
+ export interface RefreshResult {
3
+ /** True when the graph on disk was rebuilt by this call. */
4
+ refreshed: boolean;
5
+ /** What the probe found, when it ran and found something. */
6
+ drift?: Drift;
7
+ /** One-line explanation for the agent/user, when there's something worth saying. */
8
+ note?: string;
9
+ }
10
+ export interface RefreshOptions {
11
+ contextDir?: string;
12
+ /** Skip everything (the `--no-refresh` flag). */
13
+ disabled?: boolean;
14
+ }
15
+ /**
16
+ * Release the lock if this process is asked to die while holding it. Returns the
17
+ * un-hook.
18
+ *
19
+ * Not hypothetical: the Claude Code prompt hook runs `graft ask` with a timeout, and
20
+ * `execFileSync` enforces it with SIGTERM. Node's default disposition for SIGTERM is
21
+ * to exit without unwinding, so the `finally` below never runs and the lock outlives
22
+ * the process — after which the background sync is blocked and every query waits and
23
+ * then answers stale until the lock ages out. Ctrl-C on a CLI query is the same story
24
+ * with SIGINT.
25
+ *
26
+ * Adding a listener replaces that default disposition, so re-raise it explicitly
27
+ * afterwards: remove ourselves, then `process.kill(process.pid, sig)`, so the exit
28
+ * status still says "terminated by signal" for whoever is waiting on us.
29
+ */
30
+ export declare function releaseOnSignal(cache: string): () => void;
31
+ /**
32
+ * Rebuild `root`'s structural graph if the working tree has moved since the last
33
+ * build. Cheap and side-effect-free when nothing changed, which is the usual case.
34
+ *
35
+ * `root` is the repository root (the same value the query itself is given), not
36
+ * the context dir.
37
+ */
38
+ export declare function ensureFreshGraph(root: string, opts?: RefreshOptions): Promise<RefreshResult>;
39
+ /**
40
+ * Workspace variant: refresh each child repo's own graph (a workspace parent holds
41
+ * an index, never nodes). Children are independent, but they're refreshed in
42
+ * sequence — a fan-out of concurrent tree-sitter builds would spike CPU on the
43
+ * very path that's supposed to feel free.
44
+ */
45
+ export declare function ensureFreshChildren(root: string, children: string[], opts?: RefreshOptions): Promise<RefreshResult>;
46
+ /** The one-line note a CLI/MCP surface prints when a refresh actually happened.
47
+ * Null when there's nothing to say (the overwhelmingly common case). */
48
+ export declare function refreshNote(r: RefreshResult): string | null;
49
+ //# sourceMappingURL=refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../src/graph/refresh.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAmC,KAAK,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAU/E,MAAM,WAAW,aAAa;IAC5B,4DAA4D;IAC5D,SAAS,EAAE,OAAO,CAAC;IACnB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,oFAAoF;IACpF,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAcD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,IAAI,CAWzD;AAYD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,CAAC,CAwDtG;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAAE,EAClB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,aAAa,CAAC,CAsBxB;AAED;wEACwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI,CAK3D"}