@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,155 @@
|
|
|
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 { federationIds } from "../store/federation.js";
|
|
20
|
+
import { rankCorpus } from "../search/bm25f.js";
|
|
21
|
+
import { providerFromEnv } from "../embed/provider.js";
|
|
22
|
+
import { embedCorpus } from "../embed/cache.js";
|
|
23
|
+
import { cosineRank, rrf } from "../embed/hybrid.js";
|
|
24
|
+
const DEFAULT_LIMIT = 10;
|
|
25
|
+
const MAX_LIMIT = 25;
|
|
26
|
+
/**
|
|
27
|
+
* Factory for the semantic_find handler.
|
|
28
|
+
*
|
|
29
|
+
* @param store The graph store.
|
|
30
|
+
* @param repoId The active repo id.
|
|
31
|
+
* @param repoPath File system path to the repo root (for the embedding cache).
|
|
32
|
+
* @param providerOverride Inject a provider directly (for tests — avoids env/network).
|
|
33
|
+
* Pass null to force pure-lexical. Pass undefined to use env config.
|
|
34
|
+
*/
|
|
35
|
+
export function makeSemanticFind(store, repoId, repoPath = ".", providerOverride) {
|
|
36
|
+
return async (args) => {
|
|
37
|
+
const { query, kind, federated } = args;
|
|
38
|
+
const limit = Math.min(Math.max(1, args.limit ?? DEFAULT_LIMIT), MAX_LIMIT);
|
|
39
|
+
if (!query || !query.trim()) {
|
|
40
|
+
return {
|
|
41
|
+
content: [{ type: "text", text: JSON.stringify({ error: "query must be a non-empty string" }) }],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const repoIds = federated ? await federationIds(store, repoId) : [repoId];
|
|
47
|
+
// Fetch the corpus from the store (both backends return nodes sorted by id)
|
|
48
|
+
let corpus = await store.searchCorpus(repoIds);
|
|
49
|
+
// Apply optional kind filter before ranking (design §4)
|
|
50
|
+
if (kind) {
|
|
51
|
+
corpus = corpus.filter((n) => n.kind === kind);
|
|
52
|
+
}
|
|
53
|
+
// Always compute lexical ranking first (deterministic, always-reachable baseline)
|
|
54
|
+
const lexicalRanked = rankCorpus(corpus, query, MAX_LIMIT * 5);
|
|
55
|
+
// Resolve provider: override for tests, env config for production
|
|
56
|
+
const provider = providerOverride !== undefined
|
|
57
|
+
? providerOverride
|
|
58
|
+
: await providerFromEnv();
|
|
59
|
+
let ranking = "lexical";
|
|
60
|
+
let providerModelId = null;
|
|
61
|
+
let fusedResults = null;
|
|
62
|
+
// Track which list(s) each id appeared in (for the `via` field in hybrid mode)
|
|
63
|
+
let lexicalIdSet = null;
|
|
64
|
+
let cosineIdSet = null;
|
|
65
|
+
if (provider !== null) {
|
|
66
|
+
// Attempt hybrid embedding path — catch all errors → fallback to lexical
|
|
67
|
+
try {
|
|
68
|
+
const corpusVecs = await embedCorpus(provider, repoPath, corpus);
|
|
69
|
+
const queryVecs = await provider.embed([query], "query");
|
|
70
|
+
const queryVec = queryVecs[0];
|
|
71
|
+
if (queryVec && corpusVecs.size > 0) {
|
|
72
|
+
const cosineRanked = cosineRank(queryVec, corpusVecs);
|
|
73
|
+
// Build RankedItem arrays for RRF
|
|
74
|
+
const lexicalItems = lexicalRanked.map((r) => ({ id: r.node.id, score: r.score }));
|
|
75
|
+
const cosineItems = cosineRanked;
|
|
76
|
+
const fused = rrf(lexicalItems, cosineItems);
|
|
77
|
+
fusedResults = fused.map((r) => ({ id: r.id, score: r.score }));
|
|
78
|
+
ranking = "hybrid";
|
|
79
|
+
providerModelId = provider.modelId();
|
|
80
|
+
// Track membership for `via` classification
|
|
81
|
+
lexicalIdSet = new Set(lexicalItems.map((r) => r.id));
|
|
82
|
+
cosineIdSet = new Set(cosineItems.map((r) => r.id));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (e) {
|
|
86
|
+
// Any embedding error → fall back to lexical silently (log to stderr)
|
|
87
|
+
process.stderr.write(`[semantic_find] embedding error, falling back to lexical: ${e.message}\n`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Build result rows
|
|
91
|
+
const nodeById = new Map(corpus.map((n) => [n.id, n]));
|
|
92
|
+
const lexicalById = new Map(lexicalRanked.map((r) => [r.node.id, r]));
|
|
93
|
+
let rankedIds;
|
|
94
|
+
let fusedScoreById = null;
|
|
95
|
+
if (ranking === "hybrid" && fusedResults !== null) {
|
|
96
|
+
fusedScoreById = new Map(fusedResults.map((r) => [r.id, r.score]));
|
|
97
|
+
rankedIds = fusedResults.slice(0, limit).map((r) => r.id);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
rankedIds = lexicalRanked.slice(0, limit).map((r) => r.node.id);
|
|
101
|
+
}
|
|
102
|
+
const results = rankedIds.map((id) => {
|
|
103
|
+
const node = nodeById.get(id);
|
|
104
|
+
if (!node)
|
|
105
|
+
return null;
|
|
106
|
+
const lexical = lexicalById.get(id);
|
|
107
|
+
// H1: in hybrid mode surface the fused RRF score as `score`; add `via` label.
|
|
108
|
+
let score;
|
|
109
|
+
let via;
|
|
110
|
+
if (ranking === "hybrid" && fusedScoreById !== null) {
|
|
111
|
+
score = fusedScoreById.get(id) ?? 0;
|
|
112
|
+
const inLex = lexicalIdSet?.has(id) ?? false;
|
|
113
|
+
const inCos = cosineIdSet?.has(id) ?? false;
|
|
114
|
+
via = inLex && inCos ? "both" : inCos ? "embedding" : "lexical";
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
score = lexical?.score ?? 0;
|
|
118
|
+
}
|
|
119
|
+
const result = {
|
|
120
|
+
node_id: node.id,
|
|
121
|
+
qualified_name: node.qualified_name,
|
|
122
|
+
file_path: node.file_path,
|
|
123
|
+
kind: node.kind,
|
|
124
|
+
repo_id: node.repo_id,
|
|
125
|
+
score,
|
|
126
|
+
matched: lexical?.matched ?? [],
|
|
127
|
+
};
|
|
128
|
+
if (via !== undefined) {
|
|
129
|
+
result["via"] = via;
|
|
130
|
+
}
|
|
131
|
+
// Include summary only when present (keeps payload lean; absence is informative)
|
|
132
|
+
if (node.summary) {
|
|
133
|
+
result["summary"] = node.summary;
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}).filter(Boolean);
|
|
137
|
+
const response = { results };
|
|
138
|
+
// Disclose ranking mode (design §4 output shape)
|
|
139
|
+
if (ranking === "hybrid") {
|
|
140
|
+
response["ranking"] = "hybrid";
|
|
141
|
+
response["provider"] = providerModelId;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
catch (e) {
|
|
148
|
+
return {
|
|
149
|
+
content: [{ type: "text", text: e.message }],
|
|
150
|
+
isError: true,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=semanticFind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semanticFind.js","sourceRoot":"","sources":["../../src/tools/semanticFind.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool handler: get_temporal_context(path)
|
|
3
|
+
*
|
|
4
|
+
* Returns git-derived co-change, churn, and ownership signals for a file.
|
|
5
|
+
* These are advisory (derived from git history, not the committed graph) and
|
|
6
|
+
* never enter committed JSONL. Computed lazily from .git, cached by HEAD sha.
|
|
7
|
+
*/
|
|
8
|
+
import type { ToolResult } from "./readCypher.js";
|
|
9
|
+
export interface TemporalContextArgs {
|
|
10
|
+
path: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function makeTemporalContext(repoPath: string): (args: TemporalContextArgs) => Promise<ToolResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool handler: get_temporal_context(path)
|
|
3
|
+
*
|
|
4
|
+
* Returns git-derived co-change, churn, and ownership signals for a file.
|
|
5
|
+
* These are advisory (derived from git history, not the committed graph) and
|
|
6
|
+
* never enter committed JSONL. Computed lazily from .git, cached by HEAD sha.
|
|
7
|
+
*/
|
|
8
|
+
import { getTemporal } from "../temporal/temporal.js";
|
|
9
|
+
export function makeTemporalContext(repoPath) {
|
|
10
|
+
return async (args) => {
|
|
11
|
+
const result = await getTemporal(repoPath);
|
|
12
|
+
// git unavailable or repo has no history
|
|
13
|
+
if ("unavailable" in result) {
|
|
14
|
+
return {
|
|
15
|
+
content: [{
|
|
16
|
+
type: "text",
|
|
17
|
+
text: JSON.stringify({
|
|
18
|
+
unavailable: result.unavailable,
|
|
19
|
+
note: "git temporal context is not available for this repository",
|
|
20
|
+
}),
|
|
21
|
+
}],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const stats = result;
|
|
25
|
+
const filePath = args.path;
|
|
26
|
+
const fileStats = stats.files[filePath];
|
|
27
|
+
const cochanged = stats.cochange[filePath];
|
|
28
|
+
if (!fileStats) {
|
|
29
|
+
return {
|
|
30
|
+
content: [{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: JSON.stringify({
|
|
33
|
+
path: filePath,
|
|
34
|
+
head_sha: stats.head_sha,
|
|
35
|
+
note: "no history (new/untracked file or outside the window)",
|
|
36
|
+
...(stats.shallow ? { advisory: "shallow clone — history is partial" } : {}),
|
|
37
|
+
}),
|
|
38
|
+
}],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const response = {
|
|
42
|
+
path: filePath,
|
|
43
|
+
head_sha: stats.head_sha,
|
|
44
|
+
...(stats.shallow ? { advisory: "shallow clone detected — counts reflect partial history" } : {}),
|
|
45
|
+
change_count: fileStats.change_count,
|
|
46
|
+
last_changed: fileStats.last_changed,
|
|
47
|
+
top_authors: fileStats.authors,
|
|
48
|
+
co_changed: cochanged ?? [],
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=temporalContext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temporalContext.js","sourceRoot":"","sources":["../../src/tools/temporalContext.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAQtD,MAAM,UAAU,mBAAmB,CAAC,QAAgB;IAClD,OAAO,KAAK,EAAE,IAAyB,EAAuB,EAAE;QAC9D,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;QAE3C,yCAAyC;QACzC,IAAI,aAAa,IAAI,MAAM,EAAE,CAAC;YAC5B,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,WAAW,EAAE,MAAM,CAAC,WAAW;4BAC/B,IAAI,EAAE,2DAA2D;yBAClE,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,MAAuB,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;QAE3B,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,IAAI,EAAE,QAAQ;4BACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;4BACxB,IAAI,EAAE,uDAAuD;4BAC7D,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,oCAAoC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;yBAC7E,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;QAED,MAAM,QAAQ,GAA4B;YACxC,IAAI,EAAE,QAAQ;YACd,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,yDAAyD,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjG,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,YAAY,EAAE,SAAS,CAAC,YAAY;YACpC,WAAW,EAAE,SAAS,CAAC,OAAO;YAC9B,UAAU,EAAE,SAAS,IAAI,EAAE;SAC5B,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;SAC5D,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC"}
|