@reposkein/mcp 0.1.1 → 0.1.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.
- package/README.md +56 -0
- package/dist/SKILL.md +31 -0
- package/dist/embed/cache.d.ts +51 -0
- package/dist/embed/cache.js +163 -0
- package/dist/embed/cache.js.map +1 -0
- package/dist/embed/hybrid.d.ts +43 -0
- package/dist/embed/hybrid.js +106 -0
- package/dist/embed/hybrid.js.map +1 -0
- package/dist/embed/provider.d.ts +34 -0
- package/dist/embed/provider.js +32 -0
- package/dist/embed/provider.js.map +1 -0
- package/dist/embed/providers/http.d.ts +35 -0
- package/dist/embed/providers/http.js +93 -0
- package/dist/embed/providers/http.js.map +1 -0
- package/dist/embed/providers/voyage.d.ts +32 -0
- package/dist/embed/providers/voyage.js +93 -0
- package/dist/embed/providers/voyage.js.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -1
- package/dist/profile/impact.d.ts +43 -0
- package/dist/profile/impact.js +112 -0
- package/dist/profile/impact.js.map +1 -0
- package/dist/search/bm25f.d.ts +31 -0
- package/dist/search/bm25f.js +151 -0
- package/dist/search/bm25f.js.map +1 -0
- package/dist/store/GraphStore.d.ts +14 -0
- package/dist/store/GraphStore.js.map +1 -1
- package/dist/store/JsonlGraphStore.d.ts +2 -1
- package/dist/store/JsonlGraphStore.js +25 -0
- package/dist/store/JsonlGraphStore.js.map +1 -1
- package/dist/store/Neo4jGraphStore.d.ts +2 -1
- package/dist/store/Neo4jGraphStore.js +18 -0
- package/dist/store/Neo4jGraphStore.js.map +1 -1
- package/dist/store/UnconfiguredStore.d.ts +2 -1
- package/dist/store/UnconfiguredStore.js +3 -0
- package/dist/store/UnconfiguredStore.js.map +1 -1
- package/dist/temporal/gitlog.d.ts +65 -0
- package/dist/temporal/gitlog.js +254 -0
- package/dist/temporal/gitlog.js.map +1 -0
- package/dist/temporal/temporal.d.ts +22 -0
- package/dist/temporal/temporal.js +185 -0
- package/dist/temporal/temporal.js.map +1 -0
- package/dist/tools/impact.d.ts +11 -0
- package/dist/tools/impact.js +63 -0
- package/dist/tools/impact.js.map +1 -0
- package/dist/tools/semanticFind.d.ts +37 -0
- package/dist/tools/semanticFind.js +155 -0
- package/dist/tools/semanticFind.js.map +1 -0
- package/dist/tools/temporalContext.d.ts +12 -0
- package/dist/tools/temporalContext.js +55 -0
- package/dist/tools/temporalContext.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git-log mining: co-change, churn, and ownership signals.
|
|
3
|
+
*
|
|
4
|
+
* One `git log --no-merges --name-status -z --date=short` pass yields all three
|
|
5
|
+
* signals. Rename chains are reconstructed from R records so a file's history
|
|
6
|
+
* follows it across moves. Bulk commits (>K files) are excluded from co-change
|
|
7
|
+
* counting but still counted for churn. Min-support floor drops one-off pairs.
|
|
8
|
+
*
|
|
9
|
+
* All output ordering is by explicit sort keys — never Map iteration order.
|
|
10
|
+
*/
|
|
11
|
+
// ── parseGitLog ──────────────────────────────────────────────────────────────
|
|
12
|
+
/**
|
|
13
|
+
* Parse output of:
|
|
14
|
+
* git log --no-merges --name-status -z --date=short
|
|
15
|
+
* --format='%x00%H%x1f%ad%x1f%aN%x1f%aE'
|
|
16
|
+
*
|
|
17
|
+
* The `-z` flag makes git NUL-terminate each path in the name-status block.
|
|
18
|
+
* We split on NUL to get tokens, then detect the commit header lines
|
|
19
|
+
* (which start with NUL %H %ad %aN %aE joined by FS=\x1f).
|
|
20
|
+
*
|
|
21
|
+
* Rename records arrive as e.g. `R100\toldpath\0newpath\0`.
|
|
22
|
+
* With -z, git emits: <status>\0<path1>\0 and for renames <status>\0<path1>\0<path2>\0.
|
|
23
|
+
*
|
|
24
|
+
* Actual git -z --name-status output format (tested):
|
|
25
|
+
* \0<sha>\x1f<date>\x1f<name>\x1f<email>\n\n<status>\0<path>\0...<status>\0<old>\0<new>\0
|
|
26
|
+
* The commit separator is "\n\n" before the header NUL. We split entire output
|
|
27
|
+
* on the pattern "\x00\x00" (double NUL that appears between commits in -z mode)
|
|
28
|
+
* combined with the leading-NUL header.
|
|
29
|
+
*
|
|
30
|
+
* Strategy: split on NUL → walk tokens; whenever we see a token matching
|
|
31
|
+
* /^\x00<sha>\x1f.../ we start a new commit header; otherwise collect
|
|
32
|
+
* name-status entries.
|
|
33
|
+
*/
|
|
34
|
+
export function parseGitLog(raw) {
|
|
35
|
+
if (!raw.trim())
|
|
36
|
+
return [];
|
|
37
|
+
// With --format='%x00%H%x1f%ad%x1f%aN%x1f%aE' and -z, each commit header
|
|
38
|
+
// is emitted as a NUL-prefixed record. The name-status entries follow,
|
|
39
|
+
// NUL-separated, then the next commit header starts with NUL again.
|
|
40
|
+
// Split on NUL and walk tokens.
|
|
41
|
+
const tokens = raw.split("\x00");
|
|
42
|
+
const commits = [];
|
|
43
|
+
let current = null;
|
|
44
|
+
// raw file pairs for current commit before rename resolution: [status, path, ?renameTo]
|
|
45
|
+
let rawFiles = [];
|
|
46
|
+
const flush = () => {
|
|
47
|
+
if (!current)
|
|
48
|
+
return;
|
|
49
|
+
commits.push({ sha: current.sha, date: current.date, author_name: current.name, author_email: current.email, files: [] });
|
|
50
|
+
// attach raw files for post-processing (we store them temporarily)
|
|
51
|
+
commits[commits.length - 1]._raw = rawFiles;
|
|
52
|
+
rawFiles = [];
|
|
53
|
+
current = null;
|
|
54
|
+
};
|
|
55
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
56
|
+
const tok = tokens[i];
|
|
57
|
+
// Commit headers start with \x00 then SHA\x1fDATE\x1fNAME\x1fEMAIL
|
|
58
|
+
// Since we split on \x00, the header token itself (after the leading NUL
|
|
59
|
+
// is consumed by split) may look like: \nSHA\x1f... or SHA\x1f...
|
|
60
|
+
// The very first token before any NUL may be empty or contain a newline.
|
|
61
|
+
// A header token contains \x1f (field separator).
|
|
62
|
+
if (tok.includes("\x1f")) {
|
|
63
|
+
// This is a commit header (possibly with leading whitespace/newlines)
|
|
64
|
+
flush();
|
|
65
|
+
const clean = tok.replace(/^\s+/, "");
|
|
66
|
+
const parts = clean.split("\x1f");
|
|
67
|
+
if (parts.length >= 4) {
|
|
68
|
+
current = {
|
|
69
|
+
sha: parts[0].trim(),
|
|
70
|
+
date: parts[1].trim(),
|
|
71
|
+
name: parts[2].trim(),
|
|
72
|
+
email: parts[3].trim(),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
// Skip empty tokens / whitespace-only tokens (between commits, end of output)
|
|
78
|
+
const t = tok.trim();
|
|
79
|
+
if (!t)
|
|
80
|
+
continue;
|
|
81
|
+
if (!current)
|
|
82
|
+
continue; // haven't seen a commit header yet
|
|
83
|
+
// Name-status tokens: "M", "A", "D", "R100", "C100", ...
|
|
84
|
+
// In -z mode: after a status token, the next token(s) are paths.
|
|
85
|
+
// We handle this by peeking ahead.
|
|
86
|
+
if (/^[MADRCTU]\d*$/.test(t)) {
|
|
87
|
+
const status = t[0];
|
|
88
|
+
if (status === "R" || status === "C") {
|
|
89
|
+
// rename/copy: next two tokens are old-path and new-path
|
|
90
|
+
const oldPath = tokens[++i]?.trim() ?? "";
|
|
91
|
+
const newPath = tokens[++i]?.trim() ?? "";
|
|
92
|
+
if (oldPath && newPath) {
|
|
93
|
+
rawFiles.push({ status, path: oldPath, renameTo: newPath });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const path = tokens[++i]?.trim() ?? "";
|
|
98
|
+
if (path) {
|
|
99
|
+
rawFiles.push({ status, path });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// If the token doesn't match a status code and isn't empty, it's likely a
|
|
104
|
+
// stray path token already consumed above — ignore.
|
|
105
|
+
}
|
|
106
|
+
flush();
|
|
107
|
+
// ── Rename chain reconstruction ───────────────────────────────────────────
|
|
108
|
+
// Git log outputs commits newest-first. A rename record `R old → new` in
|
|
109
|
+
// commit C means: at C, the file was renamed from `old` to `new`.
|
|
110
|
+
// Any commits OLDER than C that reference `old` should be canonicalized
|
|
111
|
+
// to `new` (the current name).
|
|
112
|
+
//
|
|
113
|
+
// Algorithm: process commits in git-log order (newest first).
|
|
114
|
+
// Maintain aliasMap: old-name → current-canonical-name.
|
|
115
|
+
// - For non-rename files: apply aliasMap to get canonical name.
|
|
116
|
+
// - For rename records (R/C): add oldPath → newPath to aliasMap (so
|
|
117
|
+
// older commits referencing oldPath map to newPath). Also add oldPath
|
|
118
|
+
// as a file in this commit (it was touched — it's being renamed).
|
|
119
|
+
// The newPath is already in aliasMap for future lookups.
|
|
120
|
+
const aliasMap = new Map();
|
|
121
|
+
const resolved = commits.map((c) => {
|
|
122
|
+
const raw = c._raw ?? [];
|
|
123
|
+
const canonPaths = new Set();
|
|
124
|
+
for (const f of raw) {
|
|
125
|
+
if (f.status === "R" || f.status === "C") {
|
|
126
|
+
// This commit touched both old and new paths (it performed the rename).
|
|
127
|
+
// The canonical name for oldPath is newPath (or whatever newPath maps to).
|
|
128
|
+
if (f.renameTo) {
|
|
129
|
+
const canonNew = resolveAlias(f.renameTo, aliasMap);
|
|
130
|
+
canonPaths.add(canonNew);
|
|
131
|
+
// Record: older commits using oldPath should map to canonNew
|
|
132
|
+
aliasMap.set(f.path, canonNew);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
const canon = resolveAlias(f.path, aliasMap);
|
|
137
|
+
canonPaths.add(canon);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { ...c, files: [...canonPaths].sort() };
|
|
141
|
+
});
|
|
142
|
+
return resolved;
|
|
143
|
+
}
|
|
144
|
+
function resolveAlias(path, aliasMap) {
|
|
145
|
+
let cur = path;
|
|
146
|
+
const seen = new Set();
|
|
147
|
+
while (aliasMap.has(cur) && !seen.has(cur)) {
|
|
148
|
+
seen.add(cur);
|
|
149
|
+
cur = aliasMap.get(cur);
|
|
150
|
+
}
|
|
151
|
+
return cur;
|
|
152
|
+
}
|
|
153
|
+
// ── computeTemporal ──────────────────────────────────────────────────────────
|
|
154
|
+
export function computeTemporal(commits, opts) {
|
|
155
|
+
const K = opts.maxFilesPerCommit ?? 50;
|
|
156
|
+
const minSupport = opts.minSupport ?? 3;
|
|
157
|
+
const topCoChanged = opts.topCoChanged ?? 20;
|
|
158
|
+
const topAuthors = opts.topAuthors ?? 5;
|
|
159
|
+
// Per-file: churn counts, dates, author tallies
|
|
160
|
+
const changeCount = new Map();
|
|
161
|
+
const lastChanged = new Map();
|
|
162
|
+
const authorCommits = new Map(); // file → author_name → count
|
|
163
|
+
// Pairwise co-change counts (both directions stored): key = "a\x1fb"
|
|
164
|
+
const pairCount = new Map();
|
|
165
|
+
for (const commit of commits) {
|
|
166
|
+
const files = commit.files;
|
|
167
|
+
// ── churn (all commits including bulk) ───────────────────────────────
|
|
168
|
+
for (const f of files) {
|
|
169
|
+
changeCount.set(f, (changeCount.get(f) ?? 0) + 1);
|
|
170
|
+
const prev = lastChanged.get(f);
|
|
171
|
+
if (!prev || commit.date > prev)
|
|
172
|
+
lastChanged.set(f, commit.date);
|
|
173
|
+
// author tally
|
|
174
|
+
let am = authorCommits.get(f);
|
|
175
|
+
if (!am) {
|
|
176
|
+
am = new Map();
|
|
177
|
+
authorCommits.set(f, am);
|
|
178
|
+
}
|
|
179
|
+
am.set(commit.author_name, (am.get(commit.author_name) ?? 0) + 1);
|
|
180
|
+
}
|
|
181
|
+
// ── co-change (exclude bulk commits) ─────────────────────────────────
|
|
182
|
+
if (files.length < 2 || files.length > K)
|
|
183
|
+
continue;
|
|
184
|
+
for (let i = 0; i < files.length; i++) {
|
|
185
|
+
for (let j = i + 1; j < files.length; j++) {
|
|
186
|
+
const a = files[i];
|
|
187
|
+
const b = files[j];
|
|
188
|
+
const key = a < b ? `${a}\x1f${b}` : `${b}\x1f${a}`;
|
|
189
|
+
pairCount.set(key, (pairCount.get(key) ?? 0) + 1);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// ── Build cochange map ────────────────────────────────────────────────────
|
|
194
|
+
// For each pair with support ≥ minSupport, compute confidence(a→b) and confidence(b→a).
|
|
195
|
+
const cochangeRaw = new Map();
|
|
196
|
+
for (const [key, support] of pairCount.entries()) {
|
|
197
|
+
if (support < minSupport)
|
|
198
|
+
continue;
|
|
199
|
+
const [a, b] = key.split("\x1f");
|
|
200
|
+
const countA = changeCount.get(a) ?? 1;
|
|
201
|
+
const countB = changeCount.get(b) ?? 1;
|
|
202
|
+
const confAB = support / countA;
|
|
203
|
+
const confBA = support / countB;
|
|
204
|
+
if (!cochangeRaw.has(a))
|
|
205
|
+
cochangeRaw.set(a, []);
|
|
206
|
+
if (!cochangeRaw.has(b))
|
|
207
|
+
cochangeRaw.set(b, []);
|
|
208
|
+
cochangeRaw.get(a).push({ path: b, support, confidence: confAB });
|
|
209
|
+
cochangeRaw.get(b).push({ path: a, support, confidence: confBA });
|
|
210
|
+
}
|
|
211
|
+
// Sort each file's co-change list: confidence desc, support desc, path asc
|
|
212
|
+
const cochange = {};
|
|
213
|
+
// Sort files for deterministic output
|
|
214
|
+
const cochangeFiles = [...cochangeRaw.keys()].sort();
|
|
215
|
+
for (const f of cochangeFiles) {
|
|
216
|
+
const list = cochangeRaw.get(f);
|
|
217
|
+
list.sort((a, b) => {
|
|
218
|
+
if (b.confidence !== a.confidence)
|
|
219
|
+
return b.confidence - a.confidence;
|
|
220
|
+
if (b.support !== a.support)
|
|
221
|
+
return b.support - a.support;
|
|
222
|
+
return a.path.localeCompare(b.path);
|
|
223
|
+
});
|
|
224
|
+
cochange[f] = list.slice(0, topCoChanged);
|
|
225
|
+
}
|
|
226
|
+
// ── Build files map ───────────────────────────────────────────────────────
|
|
227
|
+
const files = {};
|
|
228
|
+
// Sort file keys for deterministic output
|
|
229
|
+
const fileKeys = [...changeCount.keys()].sort();
|
|
230
|
+
for (const f of fileKeys) {
|
|
231
|
+
const am = authorCommits.get(f) ?? new Map();
|
|
232
|
+
// Sort authors: commits desc, then name asc
|
|
233
|
+
const authors = [...am.entries()]
|
|
234
|
+
.sort(([na, ca], [nb, cb]) => {
|
|
235
|
+
if (cb !== ca)
|
|
236
|
+
return cb - ca;
|
|
237
|
+
return na.localeCompare(nb);
|
|
238
|
+
})
|
|
239
|
+
.slice(0, topAuthors)
|
|
240
|
+
.map(([name, commits]) => ({ name, commits }));
|
|
241
|
+
files[f] = {
|
|
242
|
+
change_count: changeCount.get(f) ?? 0,
|
|
243
|
+
last_changed: lastChanged.get(f) ?? "",
|
|
244
|
+
authors,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
head_sha: opts.headSha,
|
|
249
|
+
shallow: opts.shallow,
|
|
250
|
+
files,
|
|
251
|
+
cochange,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=gitlog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitlog.js","sourceRoot":"","sources":["../../src/temporal/gitlog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal context runner + sidecar cache.
|
|
3
|
+
*
|
|
4
|
+
* Shells out to `git log` via execFile, caches computed TemporalStats to
|
|
5
|
+
* .reposkein/local/temporal/<head-sha>.json (gitignored). Second call with the
|
|
6
|
+
* same HEAD sha is a cache hit (file read only).
|
|
7
|
+
*
|
|
8
|
+
* Graceful: not-a-git-repo / git-missing / empty history →
|
|
9
|
+
* { unavailable: "<reason>" } (never throws into the request).
|
|
10
|
+
*
|
|
11
|
+
* Prunes old cache files (keeps newest K=3) on each successful compute.
|
|
12
|
+
*/
|
|
13
|
+
import { type TemporalStats } from "./gitlog.js";
|
|
14
|
+
export type TemporalResult = TemporalStats | {
|
|
15
|
+
unavailable: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Compute (or load from cache) temporal stats for all files in the repo.
|
|
19
|
+
* Returns { unavailable: reason } if git is unavailable or repo has no history.
|
|
20
|
+
* Never throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function getTemporal(repoPath: string): Promise<TemporalResult>;
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Temporal context runner + sidecar cache.
|
|
3
|
+
*
|
|
4
|
+
* Shells out to `git log` via execFile, caches computed TemporalStats to
|
|
5
|
+
* .reposkein/local/temporal/<head-sha>.json (gitignored). Second call with the
|
|
6
|
+
* same HEAD sha is a cache hit (file read only).
|
|
7
|
+
*
|
|
8
|
+
* Graceful: not-a-git-repo / git-missing / empty history →
|
|
9
|
+
* { unavailable: "<reason>" } (never throws into the request).
|
|
10
|
+
*
|
|
11
|
+
* Prunes old cache files (keeps newest K=3) on each successful compute.
|
|
12
|
+
*/
|
|
13
|
+
import { execFile as execFileCb } from "node:child_process";
|
|
14
|
+
import { promisify } from "node:util";
|
|
15
|
+
import { existsSync, readFileSync, writeFileSync, renameSync, mkdirSync, readdirSync, unlinkSync, statSync, } from "node:fs";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { parseGitLog, computeTemporal } from "./gitlog.js";
|
|
18
|
+
const execFile = promisify(execFileCb);
|
|
19
|
+
/** Max cache files to keep per repo (prune oldest when exceeded). */
|
|
20
|
+
const MAX_CACHE_FILES = 3;
|
|
21
|
+
/** Window defaults (also used for cache key). */
|
|
22
|
+
const WINDOW_MONTHS = 12;
|
|
23
|
+
const MAX_COMMITS = 1000;
|
|
24
|
+
const COMMIT_SIZE_CAP = 50;
|
|
25
|
+
const MIN_SUPPORT = 3;
|
|
26
|
+
// ── git helpers ──────────────────────────────────────────────────────────────
|
|
27
|
+
async function gitExec(args, cwd) {
|
|
28
|
+
try {
|
|
29
|
+
const { stdout } = await execFile("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
|
|
30
|
+
return { stdout, ok: true };
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const e = err;
|
|
34
|
+
if (e.code === "ENOENT") {
|
|
35
|
+
return { stdout: "", ok: false, error: "git executable not found in PATH" };
|
|
36
|
+
}
|
|
37
|
+
// git exits non-zero for "not a git repo" etc.
|
|
38
|
+
const msg = e.stderr ?? e.message ?? String(err);
|
|
39
|
+
return { stdout: e.stdout ?? "", ok: false, error: msg.trim() };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function getHeadSha(repoPath) {
|
|
43
|
+
const r = await gitExec(["rev-parse", "HEAD"], repoPath);
|
|
44
|
+
if (!r.ok) {
|
|
45
|
+
// Check if it's a "not a git repo" error
|
|
46
|
+
if (r.error?.includes("not a git repository")) {
|
|
47
|
+
return { unavailable: "not a git repository" };
|
|
48
|
+
}
|
|
49
|
+
if (r.error?.includes("git executable not found")) {
|
|
50
|
+
return { unavailable: r.error };
|
|
51
|
+
}
|
|
52
|
+
// Could be an empty repo (no commits yet)
|
|
53
|
+
const check = await gitExec(["rev-parse", "--git-dir"], repoPath);
|
|
54
|
+
if (!check.ok)
|
|
55
|
+
return { unavailable: "not a git repository" };
|
|
56
|
+
return { unavailable: "repository has no commits" };
|
|
57
|
+
}
|
|
58
|
+
return { sha: r.stdout.trim() };
|
|
59
|
+
}
|
|
60
|
+
async function isShallow(repoPath) {
|
|
61
|
+
const r = await gitExec(["rev-parse", "--is-shallow-repository"], repoPath);
|
|
62
|
+
return r.ok && r.stdout.trim() === "true";
|
|
63
|
+
}
|
|
64
|
+
// ── cache helpers ─────────────────────────────────────────────────────────────
|
|
65
|
+
function cacheDir(repoPath) {
|
|
66
|
+
return join(repoPath, ".reposkein", "local", "temporal");
|
|
67
|
+
}
|
|
68
|
+
function cachePath(repoPath, headSha) {
|
|
69
|
+
return join(cacheDir(repoPath), `${headSha}.json`);
|
|
70
|
+
}
|
|
71
|
+
function readCache(path) {
|
|
72
|
+
if (!existsSync(path))
|
|
73
|
+
return null;
|
|
74
|
+
try {
|
|
75
|
+
const text = readFileSync(path, "utf8");
|
|
76
|
+
return JSON.parse(text);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/** Atomic write: write to a .tmp file then rename (best-effort on all platforms). */
|
|
83
|
+
function writeCache(path, stats) {
|
|
84
|
+
const tmp = `${path}.tmp`;
|
|
85
|
+
try {
|
|
86
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
87
|
+
writeFileSync(tmp, JSON.stringify(stats));
|
|
88
|
+
renameSync(tmp, path);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// best-effort; a write failure must not break the tool call
|
|
92
|
+
try {
|
|
93
|
+
if (existsSync(tmp))
|
|
94
|
+
unlinkSync(tmp);
|
|
95
|
+
}
|
|
96
|
+
catch { /* ignore */ }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Keep only the newest MAX_CACHE_FILES files; prune the rest (best-effort). */
|
|
100
|
+
function pruneCache(dir) {
|
|
101
|
+
try {
|
|
102
|
+
if (!existsSync(dir))
|
|
103
|
+
return;
|
|
104
|
+
const files = readdirSync(dir)
|
|
105
|
+
.filter((f) => f.endsWith(".json"))
|
|
106
|
+
.map((f) => ({ name: f, mtime: statSync(join(dir, f)).mtimeMs }))
|
|
107
|
+
.sort((a, b) => b.mtime - a.mtime); // newest first
|
|
108
|
+
for (const f of files.slice(MAX_CACHE_FILES)) {
|
|
109
|
+
try {
|
|
110
|
+
unlinkSync(join(dir, f.name));
|
|
111
|
+
}
|
|
112
|
+
catch { /* ignore */ }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// best-effort
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// ── main export ──────────────────────────────────────────────────────────────
|
|
120
|
+
/**
|
|
121
|
+
* Compute (or load from cache) temporal stats for all files in the repo.
|
|
122
|
+
* Returns { unavailable: reason } if git is unavailable or repo has no history.
|
|
123
|
+
* Never throws.
|
|
124
|
+
*/
|
|
125
|
+
export async function getTemporal(repoPath) {
|
|
126
|
+
try {
|
|
127
|
+
// 1. Resolve HEAD sha
|
|
128
|
+
const headResult = await getHeadSha(repoPath);
|
|
129
|
+
if ("unavailable" in headResult)
|
|
130
|
+
return headResult;
|
|
131
|
+
const headSha = headResult.sha;
|
|
132
|
+
// 2. Check cache
|
|
133
|
+
const cPath = cachePath(repoPath, headSha);
|
|
134
|
+
const cached = readCache(cPath);
|
|
135
|
+
if (cached)
|
|
136
|
+
return cached;
|
|
137
|
+
// 3. Detect shallow clone
|
|
138
|
+
const shallow = await isShallow(repoPath);
|
|
139
|
+
// 4. Run git log
|
|
140
|
+
const logArgs = [
|
|
141
|
+
"log",
|
|
142
|
+
"--no-merges",
|
|
143
|
+
"--name-status",
|
|
144
|
+
"-z",
|
|
145
|
+
"--date=short",
|
|
146
|
+
`--format=%x00%H%x1f%ad%x1f%aN%x1f%aE`,
|
|
147
|
+
`--since=${WINDOW_MONTHS} months ago`,
|
|
148
|
+
`-n`,
|
|
149
|
+
String(MAX_COMMITS),
|
|
150
|
+
];
|
|
151
|
+
const logResult = await gitExec(logArgs, repoPath);
|
|
152
|
+
if (!logResult.ok) {
|
|
153
|
+
return { unavailable: `git log failed: ${logResult.error ?? "unknown error"}` };
|
|
154
|
+
}
|
|
155
|
+
const raw = logResult.stdout;
|
|
156
|
+
if (!raw.trim()) {
|
|
157
|
+
// No commits in window
|
|
158
|
+
const stats = {
|
|
159
|
+
head_sha: headSha,
|
|
160
|
+
shallow,
|
|
161
|
+
files: {},
|
|
162
|
+
cochange: {},
|
|
163
|
+
};
|
|
164
|
+
writeCache(cPath, stats);
|
|
165
|
+
return stats;
|
|
166
|
+
}
|
|
167
|
+
// 5. Parse and compute
|
|
168
|
+
const commits = parseGitLog(raw);
|
|
169
|
+
const stats = computeTemporal(commits, {
|
|
170
|
+
headSha,
|
|
171
|
+
shallow,
|
|
172
|
+
maxFilesPerCommit: COMMIT_SIZE_CAP,
|
|
173
|
+
minSupport: MIN_SUPPORT,
|
|
174
|
+
});
|
|
175
|
+
// 6. Write cache and prune
|
|
176
|
+
writeCache(cPath, stats);
|
|
177
|
+
pruneCache(cacheDir(repoPath));
|
|
178
|
+
return stats;
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
// Should not reach here — but fail safe
|
|
182
|
+
return { unavailable: `unexpected error: ${err.message ?? String(err)}` };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=temporal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporal.js","sourceRoot":"","sources":["../../src/temporal/temporal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { GraphStore } from "../store/GraphStore.js";
|
|
2
|
+
import type { ToolResult } from "./readCypher.js";
|
|
3
|
+
export interface ImpactArgs {
|
|
4
|
+
node_id?: string;
|
|
5
|
+
file_path?: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
depth?: number;
|
|
8
|
+
federated?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/** Builds the impact tool handler bound to a store and repo. */
|
|
11
|
+
export declare function makeImpact(store: GraphStore, repoId: string): (args: ImpactArgs) => Promise<ToolResult>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { resolveTarget } from "../profile/resolve.js";
|
|
2
|
+
import { computeImpact } from "../profile/impact.js";
|
|
3
|
+
import { federationIds } from "../store/federation.js";
|
|
4
|
+
function clamp(val, min, max) {
|
|
5
|
+
return Math.min(Math.max(val, min), max);
|
|
6
|
+
}
|
|
7
|
+
/** Builds the impact tool handler bound to a store and repo. */
|
|
8
|
+
export function makeImpact(store, repoId) {
|
|
9
|
+
return async (args) => {
|
|
10
|
+
const sel = {
|
|
11
|
+
node_id: args.node_id,
|
|
12
|
+
file_path: args.file_path,
|
|
13
|
+
name: args.name,
|
|
14
|
+
};
|
|
15
|
+
if (!sel.node_id && !sel.name && !sel.file_path) {
|
|
16
|
+
return {
|
|
17
|
+
content: [{ type: "text", text: "provide one of: node_id, file_path+name, or name" }],
|
|
18
|
+
isError: true,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const repoIds = args.federated ? await federationIds(store, repoId) : [repoId];
|
|
23
|
+
const resolved = await resolveTarget(store, repoIds, sel);
|
|
24
|
+
if (resolved.kind === "not_found") {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: JSON.stringify({ error: "target not found" }) }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (resolved.kind === "candidates") {
|
|
31
|
+
return {
|
|
32
|
+
content: [
|
|
33
|
+
{
|
|
34
|
+
type: "text",
|
|
35
|
+
text: JSON.stringify({
|
|
36
|
+
ambiguous: true,
|
|
37
|
+
candidates: resolved.candidates.map((c) => ({
|
|
38
|
+
id: c.id,
|
|
39
|
+
name: c.qualified_name,
|
|
40
|
+
file_path: c.file_path,
|
|
41
|
+
repo_id: c.repo_id,
|
|
42
|
+
})),
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const target = resolved.target;
|
|
49
|
+
const depth = clamp(args.depth ?? 3, 1, 5);
|
|
50
|
+
const result = await computeImpact(store, repoIds, target.id, target.qualified_name, target.file_path, { depth, maxNodes: 500 });
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: JSON.stringify(result) }],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (e) {
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: e.message }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=impact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact.js","sourceRoot":"","sources":["../../src/tools/impact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* semantic_find tool — lexical (BM25F) + optional hybrid embedding entry-point discovery.
|
|
3
|
+
*
|
|
4
|
+
* Cold-start seed finder: answers "where is X?" when the agent has no node_id
|
|
5
|
+
* or exact identifier. Returns ranked node_ids ready for get_context_profile.
|
|
6
|
+
*
|
|
7
|
+
* Default behaviour (REPOSKEIN_EMBED_PROVIDER unset/none):
|
|
8
|
+
* Pure-lexical BM25F — byte-identical to the pre-embeddings baseline.
|
|
9
|
+
*
|
|
10
|
+
* With a provider configured:
|
|
11
|
+
* Hybrid: BM25F lexical + cosine similarity, fused via RRF (k=60).
|
|
12
|
+
* On ANY embedding error → silently falls back to pure-lexical (never breaks the tool).
|
|
13
|
+
* The lexical ranking is always computed first, so fallback is free.
|
|
14
|
+
*
|
|
15
|
+
* Architecture: calls store.searchCorpus to load the eligible node set, then
|
|
16
|
+
* the shared BM25F scorer ranks in TypeScript — byte-identical for both JSONL
|
|
17
|
+
* and Neo4j backends. No Neo4j vector index used.
|
|
18
|
+
*/
|
|
19
|
+
import type { GraphStore } from "../store/GraphStore.js";
|
|
20
|
+
import type { ToolResult } from "./readCypher.js";
|
|
21
|
+
import type { EmbeddingProvider } from "../embed/provider.js";
|
|
22
|
+
export interface SemanticFindArgs {
|
|
23
|
+
query: string;
|
|
24
|
+
limit?: number;
|
|
25
|
+
kind?: "Function" | "Class" | "Interface" | "Enum";
|
|
26
|
+
federated?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Factory for the semantic_find handler.
|
|
30
|
+
*
|
|
31
|
+
* @param store The graph store.
|
|
32
|
+
* @param repoId The active repo id.
|
|
33
|
+
* @param repoPath File system path to the repo root (for the embedding cache).
|
|
34
|
+
* @param providerOverride Inject a provider directly (for tests — avoids env/network).
|
|
35
|
+
* Pass null to force pure-lexical. Pass undefined to use env config.
|
|
36
|
+
*/
|
|
37
|
+
export declare function makeSemanticFind(store: GraphStore, repoId: string, repoPath?: string, providerOverride?: EmbeddingProvider | null): (args: SemanticFindArgs) => Promise<ToolResult>;
|