@nanonets/graft 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -70
- package/dist/ask/ask.d.ts +14 -0
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +24 -5
- package/dist/ask/ask.js.map +1 -1
- package/dist/claude/format.d.ts +1 -1
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +6 -3
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hooks.d.ts +15 -0
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +55 -4
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/init.d.ts +17 -0
- package/dist/claude/init.d.ts.map +1 -1
- package/dist/claude/init.js +45 -19
- package/dist/claude/init.js.map +1 -1
- package/dist/claude/settings-merge.d.ts.map +1 -1
- package/dist/claude/settings-merge.js +9 -1
- package/dist/claude/settings-merge.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +31 -8
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +2 -20
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js +9 -72
- package/dist/claude/state.js.map +1 -1
- package/dist/cli-picker.d.ts +60 -0
- package/dist/cli-picker.d.ts.map +1 -0
- package/dist/cli-picker.js +268 -0
- package/dist/cli-picker.js.map +1 -0
- package/dist/cli.js +104 -13
- package/dist/cli.js.map +1 -1
- package/dist/context/check.d.ts +21 -0
- package/dist/context/check.d.ts.map +1 -1
- package/dist/context/check.js +32 -1
- package/dist/context/check.js.map +1 -1
- package/dist/engine.d.ts +2 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -0
- package/dist/engine.js.map +1 -1
- package/dist/graph/build.d.ts +13 -2
- package/dist/graph/build.d.ts.map +1 -1
- package/dist/graph/build.js +93 -19
- package/dist/graph/build.js.map +1 -1
- package/dist/graph/extract-cache.d.ts +96 -0
- package/dist/graph/extract-cache.d.ts.map +1 -0
- package/dist/graph/extract-cache.js +199 -0
- package/dist/graph/extract-cache.js.map +1 -0
- package/dist/graph/fingerprint.d.ts +70 -0
- package/dist/graph/fingerprint.d.ts.map +1 -0
- package/dist/graph/fingerprint.js +147 -0
- package/dist/graph/fingerprint.js.map +1 -0
- package/dist/graph/load.d.ts +11 -0
- package/dist/graph/load.d.ts.map +1 -1
- package/dist/graph/load.js +14 -0
- package/dist/graph/load.js.map +1 -1
- package/dist/graph/refresh.d.ts +49 -0
- package/dist/graph/refresh.d.ts.map +1 -0
- package/dist/graph/refresh.js +202 -0
- package/dist/graph/refresh.js.map +1 -0
- package/dist/graph/source-files.d.ts +18 -0
- package/dist/graph/source-files.d.ts.map +1 -0
- package/dist/graph/source-files.js +36 -0
- package/dist/graph/source-files.js.map +1 -0
- package/dist/graph/traverse-cli.d.ts.map +1 -1
- package/dist/graph/traverse-cli.js +16 -6
- package/dist/graph/traverse-cli.js.map +1 -1
- package/dist/hosts/codex-hooks.d.ts +8 -0
- package/dist/hosts/codex-hooks.d.ts.map +1 -1
- package/dist/hosts/codex-hooks.js +27 -4
- package/dist/hosts/codex-hooks.js.map +1 -1
- package/dist/hosts/init.d.ts +2 -0
- package/dist/hosts/init.d.ts.map +1 -1
- package/dist/hosts/init.js +5 -2
- package/dist/hosts/init.js.map +1 -1
- package/dist/hosts/mcp-config.d.ts +18 -0
- package/dist/hosts/mcp-config.d.ts.map +1 -1
- package/dist/hosts/mcp-config.js +31 -7
- package/dist/hosts/mcp-config.js.map +1 -1
- package/dist/hosts/plan.d.ts +32 -0
- package/dist/hosts/plan.d.ts.map +1 -0
- package/dist/hosts/plan.js +67 -0
- package/dist/hosts/plan.js.map +1 -0
- package/dist/hosts/registry.d.ts.map +1 -1
- package/dist/hosts/registry.js +9 -0
- package/dist/hosts/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +5 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +2 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +108 -88
- package/dist/mcp/tools.js.map +1 -1
- package/dist/search/grep-cli.js +1 -1
- package/dist/search/grep-cli.js.map +1 -1
- package/dist/util/state.d.ts +45 -0
- package/dist/util/state.d.ts.map +1 -0
- package/dist/util/state.js +121 -0
- package/dist/util/state.js.map +1 -0
- package/package.json +1 -1
|
@@ -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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"}
|
package/dist/graph/load.d.ts
CHANGED
|
@@ -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
|
package/dist/graph/load.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/graph/load.js
CHANGED
|
@@ -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
|
package/dist/graph/load.js.map
CHANGED
|
@@ -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"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ensureFreshGraph` — the pre-query gate that keeps retrieval honest.
|
|
3
|
+
*
|
|
4
|
+
* Freshness used to be someone else's job: the Claude Code `Stop` hook spawned a
|
|
5
|
+
* background `graft build` *after* the turn ended, so every query an agent made
|
|
6
|
+
* between its first edit and the end of the turn answered from a graph that no
|
|
7
|
+
* longer matched the file it had just changed. Worse, an edit made outside the
|
|
8
|
+
* agent (your editor, a branch switch, a stash) set no `dirty` flag at all, so
|
|
9
|
+
* nothing ever triggered a resync.
|
|
10
|
+
*
|
|
11
|
+
* So freshness moves into the query path: every retrieval call probes the working
|
|
12
|
+
* tree (`fingerprint.ts`, ~3ms) and, when something moved, rebuilds the structural
|
|
13
|
+
* graph before answering. Properties worth keeping:
|
|
14
|
+
*
|
|
15
|
+
* - **$0 and offline.** Tier-1 only — never a summarizer, never `--deep`. Same
|
|
16
|
+
* money guard `claude/sync-run.ts` carries: auto-anything must not spend money.
|
|
17
|
+
* - **Never fatal.** A failed refresh degrades to answering from the graph on
|
|
18
|
+
* disk. A query that works today must not start failing because a rebuild did.
|
|
19
|
+
* - **Never a stampede.** It takes the same `graft/.cache/.sync.lock` the
|
|
20
|
+
* background sync uses, so concurrent MCP calls and the Stop hook can't pile up
|
|
21
|
+
* rebuilds on top of each other.
|
|
22
|
+
* - **Writes only what a query reads** (`graphOnly`): the graph, the `ask` sidecar,
|
|
23
|
+
* the freshness record. Not the markdown cards, not `INDEX.md`, not `.gitignore`.
|
|
24
|
+
* Those belong to an explicit `graft build` — which the `Stop` hook already runs
|
|
25
|
+
* at the end of a turn — so retrieval stays cheap and a read stays a read. It
|
|
26
|
+
* also leaves `stats.json` alone, so that same `Stop` hook still sees `dirty` and
|
|
27
|
+
* still rebuilds the passive surface.
|
|
28
|
+
*/
|
|
29
|
+
import { existsSync } from "node:fs";
|
|
30
|
+
import { join, resolve } from "node:path";
|
|
31
|
+
import { contextDirFor } from "../context/node-file.js";
|
|
32
|
+
import { acquireLockIn, releaseLockIn } from "../util/state.js";
|
|
33
|
+
import { CACHE_DIR } from "../context/node-file.js";
|
|
34
|
+
import { buildGraph } from "./build.js";
|
|
35
|
+
import { driftCount, isClean, probeDrift } from "./fingerprint.js";
|
|
36
|
+
import { invalidateGraphCaches } from "./load.js";
|
|
37
|
+
import { wiringPath } from "./write.js";
|
|
38
|
+
/** How long to wait for another process's in-flight rebuild before giving up and
|
|
39
|
+
* answering from the current graph. Long enough to ride out a small repo's build,
|
|
40
|
+
* short enough that a tool call never feels hung. */
|
|
41
|
+
const LOCK_WAIT_MS = 2000;
|
|
42
|
+
const LOCK_POLL_MS = 50;
|
|
43
|
+
const CLEAN = { refreshed: false };
|
|
44
|
+
/** Env kill switch, for CI or anyone who wants queries to never write. */
|
|
45
|
+
function envDisabled() {
|
|
46
|
+
const v = process.env.GRAFT_NO_REFRESH;
|
|
47
|
+
return v !== undefined && v !== "" && v !== "0" && v !== "false";
|
|
48
|
+
}
|
|
49
|
+
function sleep(ms) {
|
|
50
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Release the lock if this process is asked to die while holding it. Returns the
|
|
54
|
+
* un-hook.
|
|
55
|
+
*
|
|
56
|
+
* Not hypothetical: the Claude Code prompt hook runs `graft ask` with a timeout, and
|
|
57
|
+
* `execFileSync` enforces it with SIGTERM. Node's default disposition for SIGTERM is
|
|
58
|
+
* to exit without unwinding, so the `finally` below never runs and the lock outlives
|
|
59
|
+
* the process — after which the background sync is blocked and every query waits and
|
|
60
|
+
* then answers stale until the lock ages out. Ctrl-C on a CLI query is the same story
|
|
61
|
+
* with SIGINT.
|
|
62
|
+
*
|
|
63
|
+
* Adding a listener replaces that default disposition, so re-raise it explicitly
|
|
64
|
+
* afterwards: remove ourselves, then `process.kill(process.pid, sig)`, so the exit
|
|
65
|
+
* status still says "terminated by signal" for whoever is waiting on us.
|
|
66
|
+
*/
|
|
67
|
+
export function releaseOnSignal(cache) {
|
|
68
|
+
const signals = ["SIGTERM", "SIGINT"];
|
|
69
|
+
const onSignal = (sig) => {
|
|
70
|
+
releaseLockIn(cache);
|
|
71
|
+
for (const s of signals)
|
|
72
|
+
process.removeListener(s, onSignal);
|
|
73
|
+
process.kill(process.pid, sig);
|
|
74
|
+
};
|
|
75
|
+
for (const s of signals)
|
|
76
|
+
process.once(s, onSignal);
|
|
77
|
+
return () => {
|
|
78
|
+
for (const s of signals)
|
|
79
|
+
process.removeListener(s, onSignal);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/** Wait out someone else's rebuild, then take the lock. False when we couldn't. */
|
|
83
|
+
async function waitForLock(cache) {
|
|
84
|
+
const deadline = Date.now() + LOCK_WAIT_MS;
|
|
85
|
+
for (;;) {
|
|
86
|
+
if (acquireLockIn(cache))
|
|
87
|
+
return true;
|
|
88
|
+
if (Date.now() >= deadline)
|
|
89
|
+
return false;
|
|
90
|
+
await sleep(LOCK_POLL_MS);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Rebuild `root`'s structural graph if the working tree has moved since the last
|
|
95
|
+
* build. Cheap and side-effect-free when nothing changed, which is the usual case.
|
|
96
|
+
*
|
|
97
|
+
* `root` is the repository root (the same value the query itself is given), not
|
|
98
|
+
* the context dir.
|
|
99
|
+
*/
|
|
100
|
+
export async function ensureFreshGraph(root, opts = {}) {
|
|
101
|
+
if (opts.disabled || envDisabled())
|
|
102
|
+
return CLEAN;
|
|
103
|
+
try {
|
|
104
|
+
const dir = resolve(root);
|
|
105
|
+
const outDir = contextDirFor(dir, opts.contextDir);
|
|
106
|
+
// Nothing built yet: the caller's own "no graph — run graft build" message is
|
|
107
|
+
// the right answer. Auto-building a whole repo under a query is a surprise,
|
|
108
|
+
// and it's the one case where the user hasn't opted into graft at all yet.
|
|
109
|
+
if (!existsSync(wiringPath(outDir)))
|
|
110
|
+
return CLEAN;
|
|
111
|
+
// null = no fingerprint at all: a graph built before this mechanism existed,
|
|
112
|
+
// or by a different extractor build. Rebuild once — that lays the fingerprint
|
|
113
|
+
// down, so it costs exactly one build, not one per query.
|
|
114
|
+
const drift = probeDrift(dir, outDir);
|
|
115
|
+
if (drift && isClean(drift))
|
|
116
|
+
return CLEAN;
|
|
117
|
+
// On the default layout this is `<root>/graft/.cache/.sync.lock`, the very file
|
|
118
|
+
// the Claude Code hooks lock — so this refresh and the background sync can
|
|
119
|
+
// never rebuild at the same time.
|
|
120
|
+
const lockCache = join(outDir, CACHE_DIR);
|
|
121
|
+
if (!(await waitForLock(lockCache))) {
|
|
122
|
+
return {
|
|
123
|
+
refreshed: false,
|
|
124
|
+
drift: drift ?? undefined,
|
|
125
|
+
note: "a graph rebuild is already in flight — answering from the current graph",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const unhook = releaseOnSignal(lockCache);
|
|
129
|
+
try {
|
|
130
|
+
// We may have queued behind another process's rebuild for up to LOCK_WAIT_MS,
|
|
131
|
+
// and that rebuild very likely fixed the same drift we saw. Re-probe rather
|
|
132
|
+
// than rebuild on the strength of a stale observation: without this, four
|
|
133
|
+
// parallel MCP tool calls on one edited file produce four full rebuilds, three
|
|
134
|
+
// of them pure waste, and the last tool call pays for all of it. A null drift
|
|
135
|
+
// means "no fingerprint" and still has to build.
|
|
136
|
+
const now = drift ? probeDrift(dir, outDir) : null;
|
|
137
|
+
if (now && isClean(now)) {
|
|
138
|
+
invalidateGraphCaches(outDir);
|
|
139
|
+
return CLEAN;
|
|
140
|
+
}
|
|
141
|
+
// Tier-1 only: no summarizer, so no LLM call and no network, ever. And
|
|
142
|
+
// `graphOnly`: write the graph, the ask sidecar and the fingerprint, nothing
|
|
143
|
+
// else. The markdown projections under `graft/` stay the `Stop` hook's job —
|
|
144
|
+
// a query has no business rewriting the repo's `.gitignore` or churning every
|
|
145
|
+
// card's mtime, and skipping them is most of what keeps this cheap.
|
|
146
|
+
await buildGraph(dir, { contextDir: opts.contextDir, graphOnly: true });
|
|
147
|
+
invalidateGraphCaches(outDir);
|
|
148
|
+
return { refreshed: true, drift: drift ?? undefined };
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
unhook();
|
|
152
|
+
releaseLockIn(lockCache);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
// Answering from a slightly stale graph beats failing the query.
|
|
157
|
+
return { refreshed: false, note: `graph refresh skipped: ${err instanceof Error ? err.message : String(err)}` };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Workspace variant: refresh each child repo's own graph (a workspace parent holds
|
|
162
|
+
* an index, never nodes). Children are independent, but they're refreshed in
|
|
163
|
+
* sequence — a fan-out of concurrent tree-sitter builds would spike CPU on the
|
|
164
|
+
* very path that's supposed to feel free.
|
|
165
|
+
*/
|
|
166
|
+
export async function ensureFreshChildren(root, children, opts = {}) {
|
|
167
|
+
if (opts.disabled || envDisabled())
|
|
168
|
+
return CLEAN;
|
|
169
|
+
const refreshedIn = [];
|
|
170
|
+
let files = 0;
|
|
171
|
+
for (const child of children) {
|
|
172
|
+
// Deliberately NOT `opts`: `contextDirFor` returns an override verbatim and
|
|
173
|
+
// ignores the root it's handed, so forwarding the parent's `--dir` would point
|
|
174
|
+
// every child at the *parent's* context dir — which holds a workspace index and
|
|
175
|
+
// no wiring.json, so every child would silently be skipped. (And if it did hold
|
|
176
|
+
// one, each child would build into that single shared dir in turn, the last
|
|
177
|
+
// clobbering the rest.) A child's graph always lives in its own `<child>/graft`,
|
|
178
|
+
// which is exactly how `loadWorkspaceGraphs` reads them back.
|
|
179
|
+
const r = await ensureFreshGraph(resolve(root, child), { disabled: opts.disabled });
|
|
180
|
+
if (!r.refreshed)
|
|
181
|
+
continue;
|
|
182
|
+
refreshedIn.push(child);
|
|
183
|
+
files += r.drift ? driftCount(r.drift) : 0;
|
|
184
|
+
}
|
|
185
|
+
if (!refreshedIn.length)
|
|
186
|
+
return CLEAN;
|
|
187
|
+
return {
|
|
188
|
+
refreshed: true,
|
|
189
|
+
note: `refreshed ${refreshedIn.join(", ")} (${files || "?"} file${files === 1 ? "" : "s"} changed) before answering`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** The one-line note a CLI/MCP surface prints when a refresh actually happened.
|
|
193
|
+
* Null when there's nothing to say (the overwhelmingly common case). */
|
|
194
|
+
export function refreshNote(r) {
|
|
195
|
+
if (r.note)
|
|
196
|
+
return `[graft] ${r.note}`;
|
|
197
|
+
if (!r.refreshed)
|
|
198
|
+
return null;
|
|
199
|
+
const n = r.drift ? driftCount(r.drift) : 0;
|
|
200
|
+
return `[graft] refreshed the graph (${n || "?"} file${n === 1 ? "" : "s"} changed) before answering`;
|
|
201
|
+
}
|
|
202
|
+
//# sourceMappingURL=refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../../src/graph/refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** The source files a graph build parses: supported languages, minus the output dir. */
|
|
2
|
+
export declare function listSourceFiles(root: string, outDir: string): string[];
|
|
3
|
+
export interface SourceStat {
|
|
4
|
+
/** Absolute path. */
|
|
5
|
+
abs: string;
|
|
6
|
+
/** `relative(root, abs)` — exactly the form `buildGraph` uses for node ids and
|
|
7
|
+
* `checkGraph` diffs against, so cache keys and ids can never disagree. */
|
|
8
|
+
rel: string;
|
|
9
|
+
size: number;
|
|
10
|
+
mtimeMs: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* {@link listSourceFiles} plus each file's `(size, mtimeMs)` — the currency of
|
|
14
|
+
* both the freshness probe and the extraction cache. Files that vanish between
|
|
15
|
+
* the walk and the stat are dropped (same fail-soft posture as `walkDir`).
|
|
16
|
+
*/
|
|
17
|
+
export declare function listSourceStats(root: string, outDir: string): SourceStat[];
|
|
18
|
+
//# sourceMappingURL=source-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-files.d.ts","sourceRoot":"","sources":["../../src/graph/source-files.ts"],"names":[],"mappings":"AAaA,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAEtE;AAED,MAAM,WAAW,UAAU;IACzB,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ;+EAC2E;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,EAAE,CAY1E"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The file set a graph build parses, and its stat metadata.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `build.ts` so the freshness probe (`fingerprint.ts`) can enumerate
|
|
5
|
+
* exactly the same files without importing the builder (which would be an import
|
|
6
|
+
* cycle: build → fingerprint → build). `build.ts` re-exports
|
|
7
|
+
* {@link listSourceFiles} so its existing importers are unaffected.
|
|
8
|
+
*/
|
|
9
|
+
import { statSync } from "node:fs";
|
|
10
|
+
import { relative } from "node:path";
|
|
11
|
+
import { walkDir } from "../ingest/fs.js";
|
|
12
|
+
import { languageOf } from "./extract.js";
|
|
13
|
+
/** The source files a graph build parses: supported languages, minus the output dir. */
|
|
14
|
+
export function listSourceFiles(root, outDir) {
|
|
15
|
+
return walkDir(root).filter((f) => !f.startsWith(outDir) && languageOf(f) !== null);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* {@link listSourceFiles} plus each file's `(size, mtimeMs)` — the currency of
|
|
19
|
+
* both the freshness probe and the extraction cache. Files that vanish between
|
|
20
|
+
* the walk and the stat are dropped (same fail-soft posture as `walkDir`).
|
|
21
|
+
*/
|
|
22
|
+
export function listSourceStats(root, outDir) {
|
|
23
|
+
const out = [];
|
|
24
|
+
for (const abs of listSourceFiles(root, outDir)) {
|
|
25
|
+
let s;
|
|
26
|
+
try {
|
|
27
|
+
s = statSync(abs);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
out.push({ abs, rel: relative(root, abs), size: s.size, mtimeMs: s.mtimeMs });
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=source-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-files.js","sourceRoot":"","sources":["../../src/graph/source-files.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE1C,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAc;IAC1D,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACtF,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAc;IAC1D,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;QAChD,IAAI,CAAoC,CAAC;QACzC,IAAI,CAAC;YACH,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traverse-cli.d.ts","sourceRoot":"","sources":["../../src/graph/traverse-cli.ts"],"names":[],"mappings":"AAeA,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;kFAEkF;AAClF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;sEACsE;AACtE,wBAAgB,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAKtF;AAED;;;sCAGsC;AACtC,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,EAAE,GAC7C,OAAO,GAAG,SAAS,CAOrB;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvE;AAiDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"traverse-cli.d.ts","sourceRoot":"","sources":["../../src/graph/traverse-cli.ts"],"names":[],"mappings":"AAeA,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,EAA2B,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,iBAAiB;IAChC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,uEAAuE;IACvE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAKD;;kFAEkF;AAClF,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;sEACsE;AACtE,wBAAgB,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,CAKtF;AAED;;;sCAGsC;AACtC,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,EAAE,CAAA;CAAE,EAAE,GAC7C,OAAO,GAAG,SAAS,CAOrB;AAED,oEAAoE;AACpE,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAIvE;AAiDD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAgE3F"}
|
|
@@ -50,7 +50,7 @@ export function callersSavings(graph, results) {
|
|
|
50
50
|
export function looseNoteFor(direction, name) {
|
|
51
51
|
const label = direction === "out" ? "callees" : "callers";
|
|
52
52
|
const dir = direction === "out" ? "outgoing" : "incoming";
|
|
53
|
-
return ` no indexed ${label} — the graph has no ${dir} call/reference edges for this symbol
|
|
53
|
+
return ` no indexed ${label} — the graph has no ${dir} call/reference edges for this symbol as written. Check the name (try the bare symbol, or "Type.method"), or find its uses with graft grep "${name}". Fall back to raw grep -rn only for unindexed files`;
|
|
54
54
|
}
|
|
55
55
|
function symbolJson(n) {
|
|
56
56
|
return { id: n.id, name: n.name, kind: n.kind, path: n.path, span: n.span };
|
|
@@ -96,12 +96,22 @@ export function runCallersCommand(query, dir, opts) {
|
|
|
96
96
|
const direction = resolveDirection(opts.direction);
|
|
97
97
|
let depth = DEFAULT_DEPTH;
|
|
98
98
|
if (opts.depth !== undefined) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
// `all` (aka full/max) = the whole transitive closure: walk until no new
|
|
100
|
+
// node is reached. The BFS's visited-set makes this cycle-safe, and it
|
|
101
|
+
// terminates when the frontier empties. This is the "show me every
|
|
102
|
+
// connected source" mode — the right first move before a multi-file
|
|
103
|
+
// refactor, where stopping at direct edges misses sibling/downstream files.
|
|
104
|
+
if (/^(all|full|max)$/i.test(opts.depth)) {
|
|
105
|
+
depth = Number.POSITIVE_INFINITY;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const d = Number(opts.depth);
|
|
109
|
+
if (!Number.isFinite(d) || d < 1) {
|
|
110
|
+
console.error(`✗ --depth must be a positive number or "all", got "${opts.depth}"`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
depth = Math.floor(d);
|
|
103
114
|
}
|
|
104
|
-
depth = Math.floor(d);
|
|
105
115
|
}
|
|
106
116
|
const showDepth = depth > 1;
|
|
107
117
|
const results = matches.map((symbol) => ({ symbol, hits: edgeWalk(graph, symbol, direction, depth) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"traverse-cli.js","sourceRoot":"","sources":["../../src/graph/traverse-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAgB,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAgC,MAAM,eAAe,CAAC;AActF,MAAM,KAAK,GAAiC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAClE,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB;;kFAEkF;AAClF,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACvD,CAAC;AAED;sEACsE;AACtE,MAAM,UAAU,OAAO,CAAC,SAAoB,EAAE,GAAY,EAAE,SAAkB;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,sBAAsB,CAAC;IAClH,OAAO,KAAK,GAAG,CAAC,QAAQ,IAAI,KAAK,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;AAC1D,CAAC;AAED;;;sCAGsC;AACtC,MAAM,UAAU,cAAc,CAC5B,KAAc,EACd,OAA8C;IAE9C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,IAAI,CAAC,CAAC,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAClC,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,SAAoB,EAAE,IAAY;IAC7D,MAAM,KAAK,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC1D,MAAM,GAAG,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC;IAC1D,OAAO,gBAAgB,KAAK,uBAAuB,GAAG,
|
|
1
|
+
{"version":3,"file":"traverse-cli.js","sourceRoot":"","sources":["../../src/graph/traverse-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import type { PlannedWrite } from './plan.js';
|
|
1
2
|
export interface HookWrite {
|
|
2
3
|
id: string;
|
|
3
4
|
path: string;
|
|
4
5
|
action: 'created' | 'updated' | 'unchanged' | 'skipped-unparseable';
|
|
5
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* The files installing the Codex hook would touch — pure, no writes. Both live
|
|
9
|
+
* under `~/.codex`, so both are scoped 'global': the PostToolUse entry fires on
|
|
10
|
+
* every edit in every repo opened with Codex, not just this one. Empty when the
|
|
11
|
+
* CLI isn't installed, mirroring `installCodexHooks`' early return.
|
|
12
|
+
*/
|
|
13
|
+
export declare function hookTargets(home: string): PlannedWrite[];
|
|
6
14
|
export declare function installCodexHooks(home: string): HookWrite[];
|
|
7
15
|
//# sourceMappingURL=codex-hooks.d.ts.map
|