homegraph 1.5.2 → 1.5.3
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/CHANGELOG.md +131 -0
- package/README.md +15 -8
- package/dist/arkui/index.d.ts +4 -0
- package/dist/arkui/index.d.ts.map +1 -0
- package/dist/arkui/index.js +23 -0
- package/dist/arkui/index.js.map +1 -0
- package/dist/arkui/migrate-passage.d.ts +28 -0
- package/dist/arkui/migrate-passage.d.ts.map +1 -0
- package/dist/arkui/migrate-passage.js +310 -0
- package/dist/arkui/migrate-passage.js.map +1 -0
- package/dist/arkui/migrate-semantics.d.ts +47 -0
- package/dist/arkui/migrate-semantics.d.ts.map +1 -0
- package/dist/arkui/migrate-semantics.js +229 -0
- package/dist/arkui/migrate-semantics.js.map +1 -0
- package/dist/arkui/migrate-snapshot.d.ts +79 -0
- package/dist/arkui/migrate-snapshot.d.ts.map +1 -0
- package/dist/arkui/migrate-snapshot.js +340 -0
- package/dist/arkui/migrate-snapshot.js.map +1 -0
- package/dist/bin/fatal-handler.js +2 -2
- package/dist/bin/homegraph.js +105 -156
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +6 -15
- package/dist/bin/node-version-check.d.ts.map +1 -1
- package/dist/bin/node-version-check.js +8 -37
- package/dist/bin/node-version-check.js.map +1 -1
- package/dist/db/index.d.ts +36 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +92 -6
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +15 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +42 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +177 -10
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +6 -1
- package/dist/db/sqlite-adapter.d.ts +8 -3
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +45 -3
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/extraction/extraction-version.d.ts +1 -1
- package/dist/extraction/extraction-version.js +1 -1
- package/dist/extraction/generated-detection.d.ts +42 -11
- package/dist/extraction/generated-detection.d.ts.map +1 -1
- package/dist/extraction/generated-detection.js +141 -20
- package/dist/extraction/generated-detection.js.map +1 -1
- package/dist/extraction/index.d.ts +42 -0
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +96 -0
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +19 -2
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +460 -110
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +9 -6
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/graph-sources.d.ts +41 -0
- package/dist/graph-sources.d.ts.map +1 -0
- package/dist/graph-sources.js +82 -0
- package/dist/graph-sources.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -9
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +0 -48
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/targets/antigravity.js +1 -1
- package/dist/installer/targets/antigravity.js.map +1 -1
- package/dist/installer/targets/deveco.js +1 -1
- package/dist/installer/targets/deveco.js.map +1 -1
- package/dist/installer/targets/hermes.d.ts +1 -1
- package/dist/installer/targets/hermes.js +2 -2
- package/dist/installer/targets/hermes.js.map +1 -1
- package/dist/installer/targets/opencode.js +1 -1
- package/dist/installer/targets/opencode.js.map +1 -1
- package/dist/installer/targets/shared.js +1 -1
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/mcp/daemon-paths.d.ts +5 -4
- package/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/dist/mcp/daemon-paths.js +28 -13
- package/dist/mcp/daemon-paths.js.map +1 -1
- package/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/dist/mcp/daemon-registry.js +4 -1
- package/dist/mcp/daemon-registry.js.map +1 -1
- package/dist/mcp/daemon.d.ts +1 -1
- package/dist/mcp/daemon.js +1 -1
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +12 -3
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/explore-dedup.d.ts +137 -0
- package/dist/mcp/explore-dedup.d.ts.map +1 -0
- package/dist/mcp/explore-dedup.js +236 -0
- package/dist/mcp/explore-dedup.js.map +1 -0
- package/dist/mcp/explore-session-state.d.ts +217 -0
- package/dist/mcp/explore-session-state.d.ts.map +1 -0
- package/dist/mcp/explore-session-state.js +322 -0
- package/dist/mcp/explore-session-state.js.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +4 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +5 -14
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/query-worker.d.ts +1 -1
- package/dist/mcp/query-worker.js +1 -1
- package/dist/mcp/server-instructions.d.ts +7 -2
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +104 -28
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +14 -3
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +17 -14
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/startup-handshake.d.ts +1 -1
- package/dist/mcp/startup-handshake.js +1 -1
- package/dist/mcp/tools.d.ts +117 -7
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +3056 -503
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/frameworks/arkts-napi.d.ts +14 -0
- package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -1
- package/dist/resolution/frameworks/arkts-napi.js +169 -49
- package/dist/resolution/frameworks/arkts-napi.js.map +1 -1
- package/dist/search/query-utils.d.ts +116 -4
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +869 -60
- package/dist/search/query-utils.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/upgrade/index.d.ts +14 -26
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +28 -123
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/remove-binary.d.ts +19 -19
- package/dist/upgrade/remove-binary.d.ts.map +1 -1
- package/dist/upgrade/remove-binary.js +20 -21
- package/dist/upgrade/remove-binary.js.map +1 -1
- package/dist/upgrade/update-check.d.ts +4 -3
- package/dist/upgrade/update-check.d.ts.map +1 -1
- package/dist/upgrade/update-check.js +4 -3
- package/dist/upgrade/update-check.js.map +1 -1
- package/package.json +12 -8
- package/dist/telemetry/index.d.ts +0 -143
- package/dist/telemetry/index.d.ts.map +0 -1
- package/dist/telemetry/index.js +0 -541
- package/dist/telemetry/index.js.map +0 -1
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Cross-call source dedup for `homegraph_explore` (CG-18).
|
|
4
|
+
*
|
|
5
|
+
* The session record (CG-17) knows what earlier calls already sent. This module
|
|
6
|
+
* is the algebra that turns that record into a decision for the call being
|
|
7
|
+
* rendered: of the line ranges this call WOULD emit, which does the agent
|
|
8
|
+
* already hold, and what is genuinely new.
|
|
9
|
+
*
|
|
10
|
+
* Three rules shape everything here, and all three come from the same place —
|
|
11
|
+
* an insufficient-feeling response is what sends an agent to Read, and one or
|
|
12
|
+
* two of those early in a session teach it to abandon homegraph entirely
|
|
13
|
+
* (CLAUDE.md):
|
|
14
|
+
*
|
|
15
|
+
* 1. **A pointer, never a bare omission.** Removed source is replaced by a
|
|
16
|
+
* back-reference naming the file, the symbols, and the line span, worded so
|
|
17
|
+
* it is unmistakable that the source was already delivered IN THIS
|
|
18
|
+
* CONVERSATION and is still current. Silence reads as "homegraph didn't
|
|
19
|
+
* find it".
|
|
20
|
+
* 2. **Only prove-it dedup.** A span is withheld only when the file's bytes
|
|
21
|
+
* are byte-identical to what was served (a content fingerprint, not an
|
|
22
|
+
* mtime and not the index's drift flag). An edit between calls means the
|
|
23
|
+
* agent's copy is wrong, so the source is re-emitted in full.
|
|
24
|
+
* 3. **Cut chunks, not slivers.** Only a covered run of at least
|
|
25
|
+
* {@link EXPLORE_DEDUP.MIN_COVERED_LINES} lines is worth replacing. Below
|
|
26
|
+
* that the pointer costs more than the source, and shattering a block into
|
|
27
|
+
* one-line fragments produces exactly the ragged output that reads as a
|
|
28
|
+
* failure. Everything not withheld is emitted — where the algebra is
|
|
29
|
+
* unsure, it re-serves.
|
|
30
|
+
*
|
|
31
|
+
* Which way to be wrong, restated for this layer: re-serving something the agent
|
|
32
|
+
* has is a few hundred wasted chars; withholding something it never saw is a
|
|
33
|
+
* Read. Every threshold below leans to the first.
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EXPLORE_DEDUP = void 0;
|
|
37
|
+
exports.exploreDedupEnabled = exploreDedupEnabled;
|
|
38
|
+
exports.fileFingerprint = fileFingerprint;
|
|
39
|
+
exports.mergeRanges = mergeRanges;
|
|
40
|
+
exports.intersectRange = intersectRange;
|
|
41
|
+
exports.subtractRange = subtractRange;
|
|
42
|
+
exports.dedupeRange = dedupeRange;
|
|
43
|
+
exports.servedRangesForFile = servedRangesForFile;
|
|
44
|
+
exports.formatSpans = formatSpans;
|
|
45
|
+
exports.formatBackReference = formatBackReference;
|
|
46
|
+
exports.symbolsInSpans = symbolsInSpans;
|
|
47
|
+
const crypto_1 = require("crypto");
|
|
48
|
+
exports.EXPLORE_DEDUP = {
|
|
49
|
+
/**
|
|
50
|
+
* Shortest already-served run that may be replaced by a back-reference.
|
|
51
|
+
*
|
|
52
|
+
* Sized against what dedup is actually FOR — a later call re-serving a whole
|
|
53
|
+
* method or file it already sent. A shorter covered run is either a signature
|
|
54
|
+
* line in a skeleton render or the ±3 lines of context padding around a
|
|
55
|
+
* cluster, and swapping either for a pointer trades bytes for noise: the
|
|
56
|
+
* pointer sentence is itself ~140 chars, so under this length dedup would
|
|
57
|
+
* make the response BIGGER while making it read as full of holes.
|
|
58
|
+
*/
|
|
59
|
+
MIN_COVERED_LINES: 8,
|
|
60
|
+
/**
|
|
61
|
+
* Below this many chars of NEW source, a file's remainder is folded into its
|
|
62
|
+
* back-reference instead of being fenced on its own.
|
|
63
|
+
*
|
|
64
|
+
* The shape this exists for, seen on the CG-17 fixture: a third call whose
|
|
65
|
+
* only unheld line was the file's trailing blank one, rendered as a code fence
|
|
66
|
+
* containing `228\t`. A fence holding two lines of nothing reads as a broken
|
|
67
|
+
* response, and reading as broken is the expensive failure — it is the thing
|
|
68
|
+
* that sends an agent to Read and keeps it there. So a remainder this small is
|
|
69
|
+
* dropped rather than shown. It is the one place this module withholds
|
|
70
|
+
* something the agent has not seen, and it is bounded to ~two lines that sit
|
|
71
|
+
* directly against source the agent does hold; the file is still named, with
|
|
72
|
+
* its symbols, so one follow-up explore fetches it whole.
|
|
73
|
+
*/
|
|
74
|
+
MIN_DELTA_CHARS: 160,
|
|
75
|
+
/** Line spans named in one pointer before it summarises the rest. */
|
|
76
|
+
MAX_SPANS_IN_POINTER: 4,
|
|
77
|
+
/** Symbols named in one pointer before it summarises the rest. */
|
|
78
|
+
MAX_SYMBOLS_IN_POINTER: 5,
|
|
79
|
+
};
|
|
80
|
+
const OFF = new Set(['0', 'false', 'off', 'no']);
|
|
81
|
+
/**
|
|
82
|
+
* Kill switch: `HOMEGRAPH_EXPLORE_DEDUP=0` renders every call as if the session
|
|
83
|
+
* had no history. Read per call (not memoized) so a test can toggle it.
|
|
84
|
+
*/
|
|
85
|
+
function exploreDedupEnabled() {
|
|
86
|
+
const raw = process.env.HOMEGRAPH_EXPLORE_DEDUP;
|
|
87
|
+
if (raw === undefined)
|
|
88
|
+
return true;
|
|
89
|
+
return !OFF.has(raw.trim().toLowerCase());
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Identity of the bytes a call served for one file.
|
|
93
|
+
*
|
|
94
|
+
* This — not the index's drift flag — is what gates dedup. `isFileStaleOnDisk`
|
|
95
|
+
* answers "did the file change since the last INDEX SYNC", which is a different
|
|
96
|
+
* question with a different answer: two calls inside one drift window served the
|
|
97
|
+
* same current bytes (dedup is correct), while a file edited and re-synced
|
|
98
|
+
* between two calls is never "stale" and yet the agent's copy is now wrong
|
|
99
|
+
* (dedup would be actively harmful). Length is prefixed so a hash prefix
|
|
100
|
+
* collision cannot alias two files of different size.
|
|
101
|
+
*/
|
|
102
|
+
function fileFingerprint(content) {
|
|
103
|
+
return `${content.length}:${(0, crypto_1.createHash)('sha1').update(content).digest('hex').slice(0, 16)}`;
|
|
104
|
+
}
|
|
105
|
+
/** Sort + merge overlapping/adjacent spans into the smallest equivalent set. */
|
|
106
|
+
function mergeRanges(ranges) {
|
|
107
|
+
const valid = ranges
|
|
108
|
+
.filter((r) => Number.isFinite(r.start) && Number.isFinite(r.end) && r.end >= r.start && r.start >= 1)
|
|
109
|
+
.map((r) => ({ start: Math.floor(r.start), end: Math.floor(r.end) }))
|
|
110
|
+
.sort((a, b) => a.start - b.start || a.end - b.end);
|
|
111
|
+
const out = [];
|
|
112
|
+
for (const r of valid) {
|
|
113
|
+
const last = out[out.length - 1];
|
|
114
|
+
if (last && r.start <= last.end + 1)
|
|
115
|
+
last.end = Math.max(last.end, r.end);
|
|
116
|
+
else
|
|
117
|
+
out.push({ ...r });
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
/** The parts of `range` that `served` covers. */
|
|
122
|
+
function intersectRange(range, served) {
|
|
123
|
+
const out = [];
|
|
124
|
+
for (const s of served) {
|
|
125
|
+
const start = Math.max(range.start, s.start);
|
|
126
|
+
const end = Math.min(range.end, s.end);
|
|
127
|
+
if (end >= start)
|
|
128
|
+
out.push({ start, end });
|
|
129
|
+
}
|
|
130
|
+
return mergeRanges(out);
|
|
131
|
+
}
|
|
132
|
+
/** The parts of `range` that `cut` does NOT cover. */
|
|
133
|
+
function subtractRange(range, cut) {
|
|
134
|
+
const out = [];
|
|
135
|
+
let cursor = range.start;
|
|
136
|
+
for (const c of mergeRanges(cut)) {
|
|
137
|
+
if (c.end < cursor)
|
|
138
|
+
continue;
|
|
139
|
+
if (c.start > range.end)
|
|
140
|
+
break;
|
|
141
|
+
if (c.start > cursor)
|
|
142
|
+
out.push({ start: cursor, end: Math.min(c.start - 1, range.end) });
|
|
143
|
+
cursor = Math.max(cursor, c.end + 1);
|
|
144
|
+
if (cursor > range.end)
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
if (cursor <= range.end)
|
|
148
|
+
out.push({ start: cursor, end: range.end });
|
|
149
|
+
return out;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Split one intended span into what to emit and what to point back at.
|
|
153
|
+
*
|
|
154
|
+
* Covered runs shorter than {@link EXPLORE_DEDUP.MIN_COVERED_LINES} are left in
|
|
155
|
+
* the emit set on purpose (rule 3 above) — so a span the agent holds "almost
|
|
156
|
+
* all of" still comes back whole rather than as a stutter of fragments around
|
|
157
|
+
* pointers.
|
|
158
|
+
*/
|
|
159
|
+
function dedupeRange(range, served, minCovered = exports.EXPLORE_DEDUP.MIN_COVERED_LINES) {
|
|
160
|
+
if (served.length === 0 || range.end < range.start)
|
|
161
|
+
return { emit: [range], covered: [] };
|
|
162
|
+
const covered = intersectRange(range, served).filter((r) => r.end - r.start + 1 >= minCovered);
|
|
163
|
+
if (covered.length === 0)
|
|
164
|
+
return { emit: [range], covered: [] };
|
|
165
|
+
return { emit: subtractRange(range, covered), covered };
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Every line span this session has already served for one file, but ONLY from
|
|
169
|
+
* calls that served the SAME BYTES.
|
|
170
|
+
*
|
|
171
|
+
* A record with no fingerprint is ignored rather than trusted: it cannot prove
|
|
172
|
+
* the agent's copy matches the file on disk now, and an unprovable match is
|
|
173
|
+
* exactly the case where re-serving is right.
|
|
174
|
+
*/
|
|
175
|
+
function servedRangesForFile(prior, filePath, fingerprint) {
|
|
176
|
+
if (!prior)
|
|
177
|
+
return [];
|
|
178
|
+
const spans = [];
|
|
179
|
+
for (const call of prior.calls) {
|
|
180
|
+
for (const file of call.files) {
|
|
181
|
+
if (file.path !== filePath)
|
|
182
|
+
continue;
|
|
183
|
+
if (!file.fingerprint || file.fingerprint !== fingerprint)
|
|
184
|
+
continue;
|
|
185
|
+
spans.push(...file.ranges);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return mergeRanges(spans);
|
|
189
|
+
}
|
|
190
|
+
/** `L12`, `L12-40`, capped with a `+N more` tail. */
|
|
191
|
+
function formatSpans(spans) {
|
|
192
|
+
const shown = spans.slice(0, exports.EXPLORE_DEDUP.MAX_SPANS_IN_POINTER)
|
|
193
|
+
.map((r) => (r.start === r.end ? `L${r.start}` : `L${r.start}-${r.end}`))
|
|
194
|
+
.join(', ');
|
|
195
|
+
const more = spans.length - exports.EXPLORE_DEDUP.MAX_SPANS_IN_POINTER;
|
|
196
|
+
return more > 0 ? `${shown}, +${more} more span${more === 1 ? '' : 's'}` : shown;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The line that replaces withheld source.
|
|
200
|
+
*
|
|
201
|
+
* It has one job: make the agent reach into its own context instead of into
|
|
202
|
+
* Read. So it carries the three things needed to find the source it already has
|
|
203
|
+
* — path, symbols, line spans — plus the two facts that make using it safe:
|
|
204
|
+
* that it came from THIS conversation, and that the file has not changed since
|
|
205
|
+
* (which is checked, not asserted — see {@link fileFingerprint}). It never says
|
|
206
|
+
* "omitted", and it never steers to Read.
|
|
207
|
+
*/
|
|
208
|
+
function formatBackReference(filePath, covered, symbols, opts) {
|
|
209
|
+
const names = symbols.slice(0, exports.EXPLORE_DEDUP.MAX_SYMBOLS_IN_POINTER);
|
|
210
|
+
const moreNames = symbols.length - names.length;
|
|
211
|
+
const symbolPart = names.length > 0
|
|
212
|
+
? ` (${names.join(', ')}${moreNames > 0 ? `, +${moreNames} more` : ''})`
|
|
213
|
+
: '';
|
|
214
|
+
const head = `> **Already sent earlier in this conversation:** \`${filePath}\` ${formatSpans(covered)}${symbolPart}`;
|
|
215
|
+
const tail = opts.partial
|
|
216
|
+
? ' — unchanged on disk since, so that copy is still exact. Only the NEW lines are shown below; scroll back for the rest. Do NOT Read this file.'
|
|
217
|
+
: ' — unchanged on disk since, so that copy is still exact and is not repeated here. Use it from your context; do NOT Read this file.';
|
|
218
|
+
return head + tail;
|
|
219
|
+
}
|
|
220
|
+
/** Symbol names whose definitions fall inside the withheld spans. */
|
|
221
|
+
function symbolsInSpans(nodes, spans) {
|
|
222
|
+
const out = [];
|
|
223
|
+
const seen = new Set();
|
|
224
|
+
for (const n of nodes) {
|
|
225
|
+
if (n.kind === 'import' || n.kind === 'export')
|
|
226
|
+
continue;
|
|
227
|
+
if (!spans.some((s) => n.startLine <= s.end && (n.endLine || n.startLine) >= s.start))
|
|
228
|
+
continue;
|
|
229
|
+
if (seen.has(n.name))
|
|
230
|
+
continue;
|
|
231
|
+
seen.add(n.name);
|
|
232
|
+
out.push(n.name);
|
|
233
|
+
}
|
|
234
|
+
return out;
|
|
235
|
+
}
|
|
236
|
+
//# sourceMappingURL=explore-dedup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore-dedup.js","sourceRoot":"","sources":["../../src/mcp/explore-dedup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-scoped `homegraph_explore` call state (CG-17).
|
|
3
|
+
*
|
|
4
|
+
* What it holds: for ONE MCP session, per project it queried, what explore has
|
|
5
|
+
* already returned — the files, the line ranges of source inside them, the bytes
|
|
6
|
+
* they cost, and where in the session each call fell. Nothing else in the server
|
|
7
|
+
* knows this today: every explore call is answered as if it were the first one,
|
|
8
|
+
* which is why a 4th call happily re-serves the same spine it already sent
|
|
9
|
+
* (#1500) and why the tier's call budget can only be *asked* for rather than
|
|
10
|
+
* enforced. This module is the record those two behaviours are built on
|
|
11
|
+
* (CG-18 cross-call dedup, CG-19 budget decay). It changes no response itself.
|
|
12
|
+
*
|
|
13
|
+
* Four constraints shape the design, all of them from how the daemon actually
|
|
14
|
+
* runs:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Per session, never persisted.** One instance is owned by an
|
|
17
|
+
* {@link ../mcp/session.MCPSession} and dies with the socket. A new agent
|
|
18
|
+
* session starts clean — dedup across sessions would suppress source the
|
|
19
|
+
* new agent has never seen.
|
|
20
|
+
* 2. **Per project inside the session.** A session can query several projects
|
|
21
|
+
* by `projectPath`, so state is keyed by the RESOLVED project root
|
|
22
|
+
* (`cg.getProjectRoot()`), not by whatever path the agent typed.
|
|
23
|
+
* 3. **Bounded.** A long-lived session must not grow without limit, so
|
|
24
|
+
* everything is capped — see {@link EXPLORE_SESSION_LIMITS}. Eviction drops
|
|
25
|
+
* DETAIL only: `callCount` and `responseBytes` keep counting past it, since
|
|
26
|
+
* decay (CG-19) reads the count and must not be reset by its own bound.
|
|
27
|
+
* 4. **Daemon-safe.** The daemon shares ONE {@link ../mcp/tools.ToolHandler}
|
|
28
|
+
* (and a pool of worker threads) across every connected session, so this
|
|
29
|
+
* state can live neither on the handler nor in a worker. It lives on the
|
|
30
|
+
* session; the handler is handed it per call, and the record of what a call
|
|
31
|
+
* emitted travels back on the {@link ToolResult} so it can be recorded on
|
|
32
|
+
* the main thread whether dispatch ran in-process or on a worker.
|
|
33
|
+
*
|
|
34
|
+
* Over- vs under-reporting: where a bound forces a choice, this module keeps
|
|
35
|
+
* FEWER ranges than were emitted, never more. A consumer that under-knows
|
|
36
|
+
* re-serves something the agent already has (wasteful); one that over-knows
|
|
37
|
+
* withholds source the agent never saw (a Read — the failure this whole area
|
|
38
|
+
* exists to prevent).
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Property on a {@link ../mcp/tools.ToolResult} carrying what an explore call
|
|
42
|
+
* emitted. INTERNAL: `ToolHandler.execute` records it and deletes it before the
|
|
43
|
+
* result reaches the wire, so the agent-facing response is unchanged. It is a
|
|
44
|
+
* plain-object property (not a Symbol) on purpose — it has to survive the
|
|
45
|
+
* structured clone back from a query-pool worker.
|
|
46
|
+
*/
|
|
47
|
+
export declare const EXPLORE_EMISSION_KEY = "_hgExploreEmission";
|
|
48
|
+
/**
|
|
49
|
+
* Argument key carrying this session's prior-call view INTO a tool call. Same
|
|
50
|
+
* reasoning as {@link EXPLORE_EMISSION_KEY}: it crosses the worker boundary, so
|
|
51
|
+
* it must be a serializable property on the args object.
|
|
52
|
+
*/
|
|
53
|
+
export declare const EXPLORE_SESSION_VIEW_ARG = "_hgExploreSession";
|
|
54
|
+
/** An inclusive 1-based line span of a file that was emitted. */
|
|
55
|
+
export interface ExploreLineRange {
|
|
56
|
+
start: number;
|
|
57
|
+
end: number;
|
|
58
|
+
}
|
|
59
|
+
/** What one call emitted for one file. */
|
|
60
|
+
export interface ExploreFileEmission {
|
|
61
|
+
/** Project-relative path, exactly as the response's file header spells it. */
|
|
62
|
+
path: string;
|
|
63
|
+
/** Coalesced line spans whose source was in the response. */
|
|
64
|
+
ranges: ExploreLineRange[];
|
|
65
|
+
/** Source chars emitted for this file (excludes headers / fences). */
|
|
66
|
+
bytes: number;
|
|
67
|
+
/**
|
|
68
|
+
* Identity of the bytes those ranges were sliced from (CG-18). Cross-call
|
|
69
|
+
* dedup withholds a span only when the file still hashes to this, so an edit
|
|
70
|
+
* between two calls re-serves instead of pointing at source the agent holds a
|
|
71
|
+
* now-wrong copy of. Absent = unprovable, which dedup treats as "re-serve".
|
|
72
|
+
*/
|
|
73
|
+
fingerprint?: string;
|
|
74
|
+
/** Set when ranges were dropped to stay under the per-file bound. */
|
|
75
|
+
rangesTruncated?: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** What one explore call emitted, as reported by the handler. */
|
|
78
|
+
export interface ExploreEmission {
|
|
79
|
+
/** Resolved project root — the key state is filed under. */
|
|
80
|
+
projectRoot: string;
|
|
81
|
+
/** Normalized query text (post `normalizeQuerySpelling`). */
|
|
82
|
+
query: string;
|
|
83
|
+
files: ExploreFileEmission[];
|
|
84
|
+
/** Source chars across all files. */
|
|
85
|
+
sourceBytes: number;
|
|
86
|
+
/** Total chars of the response the agent received. */
|
|
87
|
+
responseBytes: number;
|
|
88
|
+
}
|
|
89
|
+
/** A recorded call: an emission plus where it fell in the session. */
|
|
90
|
+
export interface ExploreCallRecord extends ExploreEmission {
|
|
91
|
+
/** 1-based call index within this session FOR THIS PROJECT. Survives eviction. */
|
|
92
|
+
index: number;
|
|
93
|
+
}
|
|
94
|
+
/** Everything the session knows about one project. */
|
|
95
|
+
export interface ExploreProjectState {
|
|
96
|
+
projectRoot: string;
|
|
97
|
+
/** Explore calls made this session against this project, including evicted ones. */
|
|
98
|
+
callCount: number;
|
|
99
|
+
/** Response chars across every call, including evicted ones. */
|
|
100
|
+
responseBytes: number;
|
|
101
|
+
/** Retained call records, oldest first. Bounded — may omit early calls. */
|
|
102
|
+
calls: ExploreCallRecord[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The bounded, serializable read-view handed to a tool call. Deliberately
|
|
106
|
+
* smaller than the full state: only the most recent calls carry their ranges,
|
|
107
|
+
* because that is what a dedup/decay decision reads and the whole thing is
|
|
108
|
+
* structured-cloned to a worker on every call.
|
|
109
|
+
*/
|
|
110
|
+
export interface ExploreSessionView {
|
|
111
|
+
projects: ExploreProjectState[];
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Memory bounds. Every one of them caps DETAIL; none caps the counters that
|
|
115
|
+
* CG-19's decay reads.
|
|
116
|
+
*
|
|
117
|
+
* Sized against how sessions actually behave: an agent explores one project
|
|
118
|
+
* (occasionally a second in a monorepo) and the tier call budget is 1–5, so the
|
|
119
|
+
* retained window covers a whole realistic session and the caps only bite on
|
|
120
|
+
* pathological ones.
|
|
121
|
+
*/
|
|
122
|
+
export declare const EXPLORE_SESSION_LIMITS: {
|
|
123
|
+
/** Distinct projects kept per session; least-recently-used evicted first. */
|
|
124
|
+
readonly MAX_PROJECTS: 4;
|
|
125
|
+
/** Call records kept per project (oldest dropped; `callCount` keeps counting). */
|
|
126
|
+
readonly MAX_CALLS_RETAINED: 8;
|
|
127
|
+
/** Files kept per call — the ones that got the most source. */
|
|
128
|
+
readonly MAX_FILES_PER_CALL: 24;
|
|
129
|
+
/** Line ranges kept per file after coalescing — the largest spans. */
|
|
130
|
+
readonly MAX_RANGES_PER_FILE: 24;
|
|
131
|
+
/** Most-recent calls per project included in {@link ExploreSessionView}. */
|
|
132
|
+
readonly MAX_VIEW_CALLS: 4;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Key a project root is filed under. Resolved so `/repo` and `/repo/` agree;
|
|
136
|
+
* case-folded on the two platforms whose filesystems are case-insensitive, so a
|
|
137
|
+
* drive-letter or capitalization difference doesn't split one project in two.
|
|
138
|
+
*/
|
|
139
|
+
export declare function exploreProjectKey(projectRoot: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* Merge overlapping / adjacent spans into the smallest equivalent set, then cap
|
|
142
|
+
* it. Adjacency (`next.start <= cur.end + 1`) counts as overlap: two ranges that
|
|
143
|
+
* touch describe one contiguous block of emitted source.
|
|
144
|
+
*
|
|
145
|
+
* When the cap bites, the LARGEST spans are kept and the result is re-sorted by
|
|
146
|
+
* line so the set still reads top-to-bottom — dropping small fragments loses the
|
|
147
|
+
* least information, and under-reporting is the safe direction (see the module
|
|
148
|
+
* header).
|
|
149
|
+
*/
|
|
150
|
+
export declare function coalesceRanges(ranges: ReadonlyArray<ExploreLineRange>, max?: number): {
|
|
151
|
+
ranges: ExploreLineRange[];
|
|
152
|
+
truncated: boolean;
|
|
153
|
+
};
|
|
154
|
+
/** Whether a line falls inside any of the (sorted, coalesced) ranges. */
|
|
155
|
+
export declare function rangesCover(ranges: ReadonlyArray<ExploreLineRange>, line: number): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* One MCP session's explore history. Created per session, thrown away with it.
|
|
158
|
+
*
|
|
159
|
+
* Not thread-shared and not a singleton: two sessions on the same daemon own two
|
|
160
|
+
* instances and can never observe each other's calls. Every method is total —
|
|
161
|
+
* malformed input is normalized away rather than thrown, because this sits on
|
|
162
|
+
* the tool-call path and a bookkeeping bug must never fail an explore.
|
|
163
|
+
*/
|
|
164
|
+
export declare class ExploreSessionState {
|
|
165
|
+
/** Insertion-ordered; a touched project is re-inserted, so the head is the LRU. */
|
|
166
|
+
private readonly projects;
|
|
167
|
+
/**
|
|
168
|
+
* File an emission. Returns the record as stored (with its session call
|
|
169
|
+
* index), or `null` if the emission was unusable.
|
|
170
|
+
*/
|
|
171
|
+
record(emission: ExploreEmission): ExploreCallRecord | null;
|
|
172
|
+
/** Full state for one project, or `null` if it was never queried this session. */
|
|
173
|
+
forProject(projectRoot: string): ExploreProjectState | null;
|
|
174
|
+
/** Explore calls made this session against a project (including evicted ones). */
|
|
175
|
+
callCount(projectRoot: string): number;
|
|
176
|
+
/** Every project this session has queried, least-recently-used first. */
|
|
177
|
+
snapshot(): ExploreProjectState[];
|
|
178
|
+
/**
|
|
179
|
+
* The bounded view passed INTO a tool call. Trimmed to the most recent
|
|
180
|
+
* {@link EXPLORE_SESSION_LIMITS.MAX_VIEW_CALLS} calls per project: it crosses a
|
|
181
|
+
* worker boundary on every explore, so it carries what a dedup/decay decision
|
|
182
|
+
* needs and not the whole history.
|
|
183
|
+
*/
|
|
184
|
+
view(): ExploreSessionView;
|
|
185
|
+
/** Drop everything. Used by tests; a real session just goes away instead. */
|
|
186
|
+
clear(): void;
|
|
187
|
+
/**
|
|
188
|
+
* Fetch a project's state, creating it if new, and mark it most-recently-used.
|
|
189
|
+
* Evicts the LRU project past the bound — dropping a project entirely (rather
|
|
190
|
+
* than its detail) is right here: a session that has moved on to four other
|
|
191
|
+
* repos is not about to re-ask the first one.
|
|
192
|
+
*/
|
|
193
|
+
private touch;
|
|
194
|
+
/**
|
|
195
|
+
* Normalize + bound one call's files: coalesce each file's ranges, then keep
|
|
196
|
+
* the files that got the most source. A call that renders more files than the
|
|
197
|
+
* bound has already spread its envelope thin, so the tail files carry the
|
|
198
|
+
* least — and losing them costs the least.
|
|
199
|
+
*/
|
|
200
|
+
private boundFiles;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Read the session view a caller injected into tool args, if any. Defensive:
|
|
204
|
+
* the key is internal, but the args object comes off the wire, so a client that
|
|
205
|
+
* spells it itself gets ignored rather than trusted into a crash.
|
|
206
|
+
*/
|
|
207
|
+
export declare function readExploreSessionView(args: Record<string, unknown>): ExploreSessionView | null;
|
|
208
|
+
/**
|
|
209
|
+
* This session's prior state for one project, from an injected view.
|
|
210
|
+
*
|
|
211
|
+
* `null` means NOBODY IS TRACKING (no view was injected — the CLI, a bare
|
|
212
|
+
* handler). A view that simply hasn't seen this project yet returns an EMPTY
|
|
213
|
+
* state, not null: the distinction matters to consumers, since "first call of a
|
|
214
|
+
* tracked session" and "untracked" are different situations.
|
|
215
|
+
*/
|
|
216
|
+
export declare function viewForProject(view: ExploreSessionView | null, projectRoot: string): ExploreProjectState | null;
|
|
217
|
+
//# sourceMappingURL=explore-session-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore-session-state.d.ts","sourceRoot":"","sources":["../../src/mcp/explore-session-state.ts"],"names":[],"mappings":"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"}
|