@reposkein/mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/SKILL.md +67 -0
  2. package/dist/cli/init.d.ts +9 -0
  3. package/dist/cli/init.js +54 -0
  4. package/dist/cli/init.js.map +1 -0
  5. package/dist/guard/caps.d.ts +7 -0
  6. package/dist/guard/caps.js +22 -0
  7. package/dist/guard/caps.js.map +1 -0
  8. package/dist/guard/readonly.d.ts +4 -0
  9. package/dist/guard/readonly.js +91 -0
  10. package/dist/guard/readonly.js.map +1 -0
  11. package/dist/guard/summaryValidation.d.ts +18 -0
  12. package/dist/guard/summaryValidation.js +44 -0
  13. package/dist/guard/summaryValidation.js.map +1 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +143 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/indexer/fetchBinary.d.ts +24 -0
  18. package/dist/indexer/fetchBinary.js +109 -0
  19. package/dist/indexer/fetchBinary.js.map +1 -0
  20. package/dist/indexer/runIndexer.d.ts +26 -0
  21. package/dist/indexer/runIndexer.js +42 -0
  22. package/dist/indexer/runIndexer.js.map +1 -0
  23. package/dist/profile/assemble.d.ts +5 -0
  24. package/dist/profile/assemble.js +90 -0
  25. package/dist/profile/assemble.js.map +1 -0
  26. package/dist/profile/inline.d.ts +4 -0
  27. package/dist/profile/inline.js +32 -0
  28. package/dist/profile/inline.js.map +1 -0
  29. package/dist/profile/resolve.d.ts +10 -0
  30. package/dist/profile/resolve.js +24 -0
  31. package/dist/profile/resolve.js.map +1 -0
  32. package/dist/profile/summary.d.ts +13 -0
  33. package/dist/profile/summary.js +12 -0
  34. package/dist/profile/summary.js.map +1 -0
  35. package/dist/profile/types.d.ts +55 -0
  36. package/dist/profile/types.js +2 -0
  37. package/dist/profile/types.js.map +1 -0
  38. package/dist/store/GraphStore.d.ts +62 -0
  39. package/dist/store/GraphStore.js +9 -0
  40. package/dist/store/GraphStore.js.map +1 -0
  41. package/dist/store/JsonlGraphStore.d.ts +37 -0
  42. package/dist/store/JsonlGraphStore.js +275 -0
  43. package/dist/store/JsonlGraphStore.js.map +1 -0
  44. package/dist/store/Neo4jGraphStore.d.ts +27 -0
  45. package/dist/store/Neo4jGraphStore.js +148 -0
  46. package/dist/store/Neo4jGraphStore.js.map +1 -0
  47. package/dist/store/UnconfiguredStore.d.ts +16 -0
  48. package/dist/store/UnconfiguredStore.js +36 -0
  49. package/dist/store/UnconfiguredStore.js.map +1 -0
  50. package/dist/store/federation.d.ts +9 -0
  51. package/dist/store/federation.js +29 -0
  52. package/dist/store/federation.js.map +1 -0
  53. package/dist/store/jsonlGraph.d.ts +43 -0
  54. package/dist/store/jsonlGraph.js +176 -0
  55. package/dist/store/jsonlGraph.js.map +1 -0
  56. package/dist/store/repoId.d.ts +3 -0
  57. package/dist/store/repoId.js +18 -0
  58. package/dist/store/repoId.js.map +1 -0
  59. package/dist/store/sidecar.d.ts +16 -0
  60. package/dist/store/sidecar.js +65 -0
  61. package/dist/store/sidecar.js.map +1 -0
  62. package/dist/tools/getContextProfile.d.ts +10 -0
  63. package/dist/tools/getContextProfile.js +44 -0
  64. package/dist/tools/getContextProfile.js.map +1 -0
  65. package/dist/tools/indexerTools.d.ts +27 -0
  66. package/dist/tools/indexerTools.js +89 -0
  67. package/dist/tools/indexerTools.js.map +1 -0
  68. package/dist/tools/readCypher.d.ts +16 -0
  69. package/dist/tools/readCypher.js +40 -0
  70. package/dist/tools/readCypher.js.map +1 -0
  71. package/dist/tools/writeSemanticSummary.d.ts +8 -0
  72. package/dist/tools/writeSemanticSummary.js +40 -0
  73. package/dist/tools/writeSemanticSummary.js.map +1 -0
  74. package/package.json +35 -0
  75. package/scripts/bundle-skill.mjs +19 -0
  76. package/scripts/postinstall.mjs +19 -0
@@ -0,0 +1,275 @@
1
+ import { statSync, readFileSync, existsSync } from "node:fs";
2
+ import { join, resolve, isAbsolute, sep } from "node:path";
3
+ import { CypherUnsupportedError, } from "./GraphStore.js";
4
+ import { buildFederatedGraph, emptyGraph, } from "./jsonlGraph.js";
5
+ import { readSidecar, upsertSidecar, sidecarPath } from "./sidecar.js";
6
+ function str(v) {
7
+ return typeof v === "string" ? v : null;
8
+ }
9
+ function num(v) {
10
+ return typeof v === "number" ? v : 0;
11
+ }
12
+ /** Resolves a federated child dir from an untrusted committed root_path,
13
+ * rejecting absolute paths, `..`, and anything escaping `base`. */
14
+ function safeChildDir(base, rootPath) {
15
+ if (isAbsolute(rootPath))
16
+ return null;
17
+ if (rootPath.split(/[\\/]/).includes(".."))
18
+ return null;
19
+ const baseAbs = resolve(base);
20
+ const childAbs = resolve(baseAbs, rootPath);
21
+ if (childAbs === baseAbs || childAbs.startsWith(baseAbs + sep))
22
+ return childAbs;
23
+ return null;
24
+ }
25
+ function toTargetRow(n) {
26
+ const name = str(n.props.name) ?? "";
27
+ return {
28
+ id: n.id,
29
+ repo_id: n.repoId,
30
+ name,
31
+ qualified_name: str(n.props.qualified_name) ?? name,
32
+ file_path: str(n.props.file_path) ?? "",
33
+ start_line: num(n.props.start_line),
34
+ end_line: num(n.props.end_line),
35
+ semantic_summary: str(n.props.semantic_summary),
36
+ summary_of_hash: str(n.props.summary_of_hash),
37
+ content_hash: str(n.props.content_hash),
38
+ labels: n.labels.filter((l) => l !== "Rs"),
39
+ };
40
+ }
41
+ function toNeighborRow(n, edgeProps) {
42
+ const row = {
43
+ id: n.id,
44
+ repo_id: n.repoId,
45
+ name: str(n.props.qualified_name) ?? str(n.props.name) ?? "",
46
+ semantic_summary: str(n.props.semantic_summary),
47
+ summary_of_hash: str(n.props.summary_of_hash),
48
+ content_hash: str(n.props.content_hash),
49
+ };
50
+ if (edgeProps) {
51
+ if (typeof edgeProps.resolution === "string")
52
+ row.resolution = edgeProps.resolution;
53
+ if (typeof edgeProps.confidence === "number")
54
+ row.confidence = edgeProps.confidence;
55
+ if (edgeProps.cross_repo === true)
56
+ row.cross_repo = true;
57
+ }
58
+ return row;
59
+ }
60
+ const hasLabel = (n, l) => n.labels.includes(l);
61
+ /** A GraphStore over a repo's committed .reposkein JSONL. In single-repo mode
62
+ * it loads only the root; in federated mode it also loads nested children
63
+ * (guarded, cycle-safe) and merges them into one graph. All read methods
64
+ * scope per-node by repoIds — so non-federated reads (repoIds=[root]) see
65
+ * exactly the root (children invisible).
66
+ *
67
+ * Reloads when either ROOT JSONL file's mtime changes (v1: a child-only
68
+ * change without a root change won't trigger reload — acceptable).
69
+ * writeSummary persists to the durable sidecar (.reposkein/local/summaries.jsonl). */
70
+ export class JsonlGraphStore {
71
+ repoId;
72
+ graph = emptyGraph();
73
+ mtime = -1;
74
+ repoPath;
75
+ nodesPath;
76
+ edgesPath;
77
+ sidecarFile;
78
+ constructor(repoPath, repoId) {
79
+ this.repoId = repoId;
80
+ this.repoPath = repoPath;
81
+ const dir = join(repoPath, ".reposkein");
82
+ this.nodesPath = join(dir, "nodes.jsonl");
83
+ this.edgesPath = join(dir, "edges.jsonl");
84
+ this.sidecarFile = sidecarPath(repoPath);
85
+ this.ensureFresh();
86
+ }
87
+ /** Gathers committed JSONL for the root + all transitively federated
88
+ * children (guarded, cycle-safe). Each child's repo_id comes from the proxy
89
+ * Repository node's federated_repo_id in the parent's nodes.jsonl. */
90
+ collectRepos() {
91
+ const repos = [];
92
+ const seen = new Set();
93
+ const visit = (dir, repoId) => {
94
+ if (seen.has(repoId))
95
+ return;
96
+ seen.add(repoId);
97
+ const nodesPath = join(dir, ".reposkein", "nodes.jsonl");
98
+ const edgesPath = join(dir, ".reposkein", "edges.jsonl");
99
+ let nodesText = "";
100
+ let edgesText = "";
101
+ try {
102
+ if (existsSync(nodesPath))
103
+ nodesText = readFileSync(nodesPath, "utf8");
104
+ if (existsSync(edgesPath))
105
+ edgesText = readFileSync(edgesPath, "utf8");
106
+ }
107
+ catch {
108
+ return;
109
+ }
110
+ repos.push({ repoId, nodesText, edgesText });
111
+ // Discover children from this repo's Repository proxy nodes.
112
+ for (const line of nodesText.split("\n")) {
113
+ if (line.trim() === "")
114
+ continue;
115
+ let obj;
116
+ try {
117
+ obj = JSON.parse(line);
118
+ }
119
+ catch {
120
+ continue;
121
+ }
122
+ const labels = Array.isArray(obj.labels) ? obj.labels : [];
123
+ if (!labels.includes("Repository"))
124
+ continue;
125
+ const fid = obj.federated_repo_id;
126
+ const rp = obj.root_path;
127
+ if (typeof fid === "string" && typeof rp === "string" && rp !== ".") {
128
+ const childDir = safeChildDir(dir, rp);
129
+ if (childDir)
130
+ visit(childDir, fid);
131
+ }
132
+ }
133
+ };
134
+ visit(this.repoPath, this.repoId);
135
+ return repos;
136
+ }
137
+ /** Reloads the graph if either ROOT file's mtime changed since last load. */
138
+ ensureFresh() {
139
+ let m = 0;
140
+ try {
141
+ if (existsSync(this.nodesPath))
142
+ m = Math.max(m, statSync(this.nodesPath).mtimeMs);
143
+ if (existsSync(this.edgesPath))
144
+ m = Math.max(m, statSync(this.edgesPath).mtimeMs);
145
+ }
146
+ catch {
147
+ m = 0;
148
+ }
149
+ if (m === this.mtime)
150
+ return;
151
+ this.mtime = m;
152
+ try {
153
+ this.graph = buildFederatedGraph(this.collectRepos());
154
+ // Overlay the ROOT's durable sidecar summaries (child sidecars are their
155
+ // own concern; v1 overlays the active repo only).
156
+ for (const [id, rec] of readSidecar(this.sidecarFile)) {
157
+ const n = this.graph.byId.get(id);
158
+ if (n) {
159
+ n.props.semantic_summary = rec.semantic_summary;
160
+ n.props.summary_of_hash = rec.summary_of_hash;
161
+ n.props.summary_model = rec.summary_model;
162
+ n.props.summary_at = rec.summary_at;
163
+ n.props.summary_by = rec.summary_by;
164
+ }
165
+ }
166
+ }
167
+ catch {
168
+ this.graph = emptyGraph();
169
+ }
170
+ }
171
+ async getNode(repoIds, id) {
172
+ this.ensureFresh();
173
+ const n = this.graph.byId.get(id);
174
+ return n && repoIds.includes(n.repoId) ? toTargetRow(n) : null;
175
+ }
176
+ async resolveByPathAndName(repoIds, filePath, name) {
177
+ this.ensureFresh();
178
+ return this.graph.nodes
179
+ .filter((n) => repoIds.includes(n.repoId) &&
180
+ str(n.props.file_path) === filePath &&
181
+ (hasLabel(n, "Function") || hasLabel(n, "Class")) &&
182
+ (str(n.props.name) === name || str(n.props.qualified_name) === name))
183
+ .map(toTargetRow);
184
+ }
185
+ async resolveByName(repoIds, name) {
186
+ this.ensureFresh();
187
+ return this.graph.nodes
188
+ .filter((n) => repoIds.includes(n.repoId) && hasLabel(n, "Function") && str(n.props.name) === name)
189
+ .map(toTargetRow);
190
+ }
191
+ async callers(repoIds, id, limit) {
192
+ this.ensureFresh();
193
+ const rows = [];
194
+ for (const e of this.graph.callsTo.get(id) ?? []) {
195
+ const x = this.graph.byId.get(e.from);
196
+ if (x && hasLabel(x, "Function") && repoIds.includes(x.repoId))
197
+ rows.push(toNeighborRow(x, e.props));
198
+ }
199
+ rows.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
200
+ return rows.slice(0, limit);
201
+ }
202
+ async callees(repoIds, id, limit) {
203
+ this.ensureFresh();
204
+ const rows = [];
205
+ for (const e of this.graph.callsFrom.get(id) ?? []) {
206
+ const x = this.graph.byId.get(e.to);
207
+ if (x && hasLabel(x, "Function") && repoIds.includes(x.repoId))
208
+ rows.push(toNeighborRow(x, e.props));
209
+ }
210
+ rows.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
211
+ return rows.slice(0, limit);
212
+ }
213
+ async calleesAt2Hops(repoIds, id, limit) {
214
+ this.ensureFresh();
215
+ const seen = new Map();
216
+ for (const e1 of this.graph.callsFrom.get(id) ?? []) {
217
+ for (const e2 of this.graph.callsFrom.get(e1.to) ?? []) {
218
+ const x = this.graph.byId.get(e2.to);
219
+ if (x && hasLabel(x, "Function") && repoIds.includes(x.repoId) && !seen.has(x.id)) {
220
+ seen.set(x.id, toNeighborRow(x));
221
+ }
222
+ }
223
+ }
224
+ return [...seen.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)).slice(0, limit);
225
+ }
226
+ async writeSummary(repoId, id, fields) {
227
+ this.ensureFresh();
228
+ if (repoId !== this.repoId)
229
+ return { kind: "not_found" };
230
+ const n = this.graph.byId.get(id);
231
+ if (!n || n.repoId !== this.repoId)
232
+ return { kind: "not_found" };
233
+ const chash = str(n.props.content_hash);
234
+ if (chash === null)
235
+ return { kind: "no_content_hash" };
236
+ const oldSummary = str(n.props.semantic_summary);
237
+ const oldHash = str(n.props.summary_of_hash);
238
+ const stale_replaced = oldSummary !== null && oldHash !== chash;
239
+ n.props.semantic_summary = fields.summary;
240
+ n.props.summary_of_hash = chash;
241
+ n.props.summary_model = fields.model;
242
+ n.props.summary_at = fields.at;
243
+ n.props.summary_by = fields.by;
244
+ upsertSidecar(this.sidecarFile, {
245
+ id,
246
+ semantic_summary: fields.summary,
247
+ summary_of_hash: chash,
248
+ summary_model: fields.model,
249
+ summary_at: fields.at,
250
+ summary_by: fields.by,
251
+ });
252
+ return { kind: "ok", stale_replaced };
253
+ }
254
+ async federatedRepoIds(repoId) {
255
+ this.ensureFresh();
256
+ if (repoId !== this.repoId)
257
+ return [];
258
+ const ids = [];
259
+ for (const n of this.graph.nodes) {
260
+ if (n.repoId === this.repoId && hasLabel(n, "Repository")) {
261
+ const fid = str(n.props.federated_repo_id);
262
+ if (fid)
263
+ ids.push(fid);
264
+ }
265
+ }
266
+ return ids;
267
+ }
268
+ async runRead() {
269
+ throw new CypherUnsupportedError();
270
+ }
271
+ async close() {
272
+ // nothing to close
273
+ }
274
+ }
275
+ //# sourceMappingURL=JsonlGraphStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JsonlGraphStore.js","sourceRoot":"","sources":["../../src/store/JsonlGraphStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { GraphStore, NeighborRow, SummaryFields, WriteSummaryResult } from "./GraphStore.js";
2
+ import type { TargetRow } from "../profile/types.js";
3
+ export declare class Neo4jGraphStore implements GraphStore {
4
+ private driver;
5
+ constructor(uri: string, user: string, password: string);
6
+ /** Connect using env: NEO4J_URI / NEO4J_USER / NEO4J_PASSWORD. */
7
+ static fromEnv(): Neo4jGraphStore;
8
+ private static TARGET_RETURN;
9
+ private static NEIGHBOR_RETURN;
10
+ private static toTargetRow;
11
+ private static toNeighborRow;
12
+ getNode(repoIds: string[], id: string): Promise<TargetRow | null>;
13
+ resolveByPathAndName(repoIds: string[], filePath: string, name: string): Promise<TargetRow[]>;
14
+ resolveByName(repoIds: string[], name: string): Promise<TargetRow[]>;
15
+ callers(repoIds: string[], id: string, limit: number): Promise<NeighborRow[]>;
16
+ callees(repoIds: string[], id: string, limit: number): Promise<NeighborRow[]>;
17
+ calleesAt2Hops(repoIds: string[], id: string, limit: number): Promise<NeighborRow[]>;
18
+ writeSummary(repoId: string, id: string, fields: SummaryFields): Promise<WriteSummaryResult>;
19
+ federatedRepoIds(repoId: string): Promise<string[]>;
20
+ runRead(query: string, params?: Record<string, unknown>, opts?: {
21
+ timeoutMs?: number;
22
+ }): Promise<Record<string, unknown>[]>;
23
+ runWrite(query: string, params?: Record<string, unknown>, opts?: {
24
+ timeoutMs?: number;
25
+ }): Promise<Record<string, unknown>[]>;
26
+ close(): Promise<void>;
27
+ }
@@ -0,0 +1,148 @@
1
+ import neo4j from "neo4j-driver";
2
+ export class Neo4jGraphStore {
3
+ driver;
4
+ constructor(uri, user, password) {
5
+ this.driver = neo4j.driver(uri, neo4j.auth.basic(user, password), {
6
+ disableLosslessIntegers: true,
7
+ });
8
+ }
9
+ /** Connect using env: NEO4J_URI / NEO4J_USER / NEO4J_PASSWORD. */
10
+ static fromEnv() {
11
+ const uri = process.env.NEO4J_URI ?? "neo4j://localhost:7687";
12
+ const user = process.env.NEO4J_USER ?? "neo4j";
13
+ const password = process.env.NEO4J_PASSWORD;
14
+ if (!password)
15
+ throw new Error("NEO4J_PASSWORD must be set");
16
+ return new Neo4jGraphStore(uri, user, password);
17
+ }
18
+ // Projection for a resolved target node (was resolve.ts TARGET_RETURN).
19
+ static TARGET_RETURN = "t.id AS id, t.name AS name, t.qualified_name AS qualified_name, t.file_path AS file_path, " +
20
+ "t.start_line AS start_line, t.end_line AS end_line, t.semantic_summary AS semantic_summary, " +
21
+ "t.summary_of_hash AS summary_of_hash, t.content_hash AS content_hash, " +
22
+ "[l IN labels(t) WHERE l <> 'Rs'] AS labels, t.repo_id AS repo_id";
23
+ // Projection for a neighbor node (was assemble.ts NEIGHBOR_RETURN). Caller
24
+ // prefixes `x.id ` and may append edge props.
25
+ static NEIGHBOR_RETURN = "AS id, x.qualified_name AS name, x.semantic_summary AS semantic_summary, " +
26
+ "x.summary_of_hash AS summary_of_hash, x.content_hash AS content_hash, x.repo_id AS repo_id";
27
+ static toTargetRow(r) {
28
+ return {
29
+ id: r.id,
30
+ repo_id: r.repo_id ?? "",
31
+ name: r.name,
32
+ qualified_name: r.qualified_name ?? r.name,
33
+ file_path: r.file_path ?? "",
34
+ start_line: r.start_line ?? 0,
35
+ end_line: r.end_line ?? 0,
36
+ semantic_summary: r.semantic_summary ?? null,
37
+ summary_of_hash: r.summary_of_hash ?? null,
38
+ content_hash: r.content_hash ?? null,
39
+ labels: r.labels ?? [],
40
+ };
41
+ }
42
+ static toNeighborRow(r) {
43
+ const row = {
44
+ id: r.id,
45
+ name: r.name ?? "",
46
+ semantic_summary: r.semantic_summary ?? null,
47
+ summary_of_hash: r.summary_of_hash ?? null,
48
+ content_hash: r.content_hash ?? null,
49
+ };
50
+ if (r.resolution !== undefined && r.resolution !== null)
51
+ row.resolution = r.resolution;
52
+ if (r.confidence !== undefined && r.confidence !== null)
53
+ row.confidence = r.confidence;
54
+ if (typeof r.repo_id === "string")
55
+ row.repo_id = r.repo_id;
56
+ if (r.cross_repo === true)
57
+ row.cross_repo = true;
58
+ return row;
59
+ }
60
+ async getNode(repoIds, id) {
61
+ const rows = await this.runRead(`MATCH (t:Rs {id:$id}) WHERE t.repo_id IN $repo_ids RETURN ${Neo4jGraphStore.TARGET_RETURN}`, { id, repo_ids: repoIds });
62
+ return rows.length === 1 ? Neo4jGraphStore.toTargetRow(rows[0]) : null;
63
+ }
64
+ async resolveByPathAndName(repoIds, filePath, name) {
65
+ const rows = await this.runRead(`MATCH (t:Rs {file_path:$path}) ` +
66
+ `WHERE t.repo_id IN $repo_ids AND (t.name = $name OR t.qualified_name = $name) AND (t:Function OR t:Class) ` +
67
+ `RETURN ${Neo4jGraphStore.TARGET_RETURN}`, { repo_ids: repoIds, path: filePath, name });
68
+ return rows.map(Neo4jGraphStore.toTargetRow);
69
+ }
70
+ async resolveByName(repoIds, name) {
71
+ const rows = await this.runRead(`MATCH (t:Function {name:$name}) WHERE t.repo_id IN $repo_ids RETURN ${Neo4jGraphStore.TARGET_RETURN}`, { repo_ids: repoIds, name });
72
+ return rows.map(Neo4jGraphStore.toTargetRow);
73
+ }
74
+ async callers(repoIds, id, limit) {
75
+ const rows = await this.runRead(`MATCH (x:Function)-[r:CALLS]->(t:Rs {id:$id}) WHERE x.repo_id IN $repo_ids ` +
76
+ `RETURN x.id ${Neo4jGraphStore.NEIGHBOR_RETURN}, r.resolution AS resolution, r.confidence AS confidence, r.cross_repo AS cross_repo ` +
77
+ `ORDER BY x.id LIMIT $limit`, { id, repo_ids: repoIds, limit: neo4j.int(limit) });
78
+ return rows.map(Neo4jGraphStore.toNeighborRow);
79
+ }
80
+ async callees(repoIds, id, limit) {
81
+ const rows = await this.runRead(`MATCH (t:Rs {id:$id})-[r:CALLS]->(x:Function) WHERE x.repo_id IN $repo_ids ` +
82
+ `RETURN x.id ${Neo4jGraphStore.NEIGHBOR_RETURN}, r.resolution AS resolution, r.confidence AS confidence, r.cross_repo AS cross_repo ` +
83
+ `ORDER BY x.id LIMIT $limit`, { id, repo_ids: repoIds, limit: neo4j.int(limit) });
84
+ return rows.map(Neo4jGraphStore.toNeighborRow);
85
+ }
86
+ async calleesAt2Hops(repoIds, id, limit) {
87
+ const rows = await this.runRead(`MATCH (t:Rs {id:$id})-[:CALLS*2..2]->(x:Function) WHERE x.repo_id IN $repo_ids ` +
88
+ `RETURN DISTINCT x.id ${Neo4jGraphStore.NEIGHBOR_RETURN} ` +
89
+ `ORDER BY x.id LIMIT $limit`, { id, repo_ids: repoIds, limit: neo4j.int(limit) });
90
+ return rows.map(Neo4jGraphStore.toNeighborRow);
91
+ }
92
+ async writeSummary(repoId, id, fields) {
93
+ const rows = await this.runRead("MATCH (n:Rs {id:$id, repo_id:$repo}) " +
94
+ "RETURN n.content_hash AS chash, n.semantic_summary AS old, n.summary_of_hash AS oldhash", { id, repo: repoId });
95
+ if (rows.length === 0)
96
+ return { kind: "not_found" };
97
+ const row = rows[0];
98
+ if (row.chash === null || row.chash === undefined) {
99
+ return { kind: "no_content_hash" };
100
+ }
101
+ const stale_replaced = row.old != null && (row.oldhash ?? null) !== (row.chash ?? null);
102
+ await this.runWrite("MATCH (n:Rs {id:$id, repo_id:$repo}) " +
103
+ "SET n.semantic_summary=$s, n.summary_of_hash=n.content_hash, " +
104
+ "n.summary_model=$m, n.summary_at=$at, n.summary_by=$by", { id, repo: repoId, s: fields.summary, m: fields.model, at: fields.at, by: fields.by });
105
+ return { kind: "ok", stale_replaced };
106
+ }
107
+ async federatedRepoIds(repoId) {
108
+ const rows = await this.runRead("MATCH (r:Repository {repo_id: $repo_id, root_path: '.'})-[:FEDERATES_TO*1..8]->(x:Repository) " +
109
+ "WHERE x.federated_repo_id IS NOT NULL RETURN DISTINCT x.federated_repo_id AS id", { repo_id: repoId }, { timeoutMs: 5000 });
110
+ const ids = [];
111
+ for (const r of rows)
112
+ if (typeof r.id === "string")
113
+ ids.push(r.id);
114
+ return ids;
115
+ }
116
+ async runRead(query, params = {}, opts = {}) {
117
+ const session = this.driver.session({
118
+ defaultAccessMode: neo4j.session.READ,
119
+ });
120
+ try {
121
+ const result = await session.run(query, params, {
122
+ timeout: opts.timeoutMs ?? 10_000,
123
+ });
124
+ return result.records.map((r) => r.toObject());
125
+ }
126
+ finally {
127
+ await session.close();
128
+ }
129
+ }
130
+ async runWrite(query, params = {}, opts = {}) {
131
+ const session = this.driver.session({
132
+ defaultAccessMode: neo4j.session.WRITE,
133
+ });
134
+ try {
135
+ const result = await session.run(query, params, {
136
+ timeout: opts.timeoutMs ?? 10_000,
137
+ });
138
+ return result.records.map((r) => r.toObject());
139
+ }
140
+ finally {
141
+ await session.close();
142
+ }
143
+ }
144
+ async close() {
145
+ await this.driver.close();
146
+ }
147
+ }
148
+ //# sourceMappingURL=Neo4jGraphStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Neo4jGraphStore.js","sourceRoot":"","sources":["../../src/store/Neo4jGraphStore.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { GraphStore, NeighborRow, SummaryFields, WriteSummaryResult } from "./GraphStore.js";
2
+ import type { TargetRow } from "../profile/types.js";
3
+ /** A no-op store used when NEO4J_PASSWORD is absent.
4
+ * All operations reject with an instructive error. */
5
+ export declare class UnconfiguredStore implements GraphStore {
6
+ getNode(_repoIds: string[], _id: string): Promise<TargetRow | null>;
7
+ resolveByPathAndName(): Promise<TargetRow[]>;
8
+ resolveByName(): Promise<TargetRow[]>;
9
+ callers(): Promise<NeighborRow[]>;
10
+ callees(): Promise<NeighborRow[]>;
11
+ calleesAt2Hops(): Promise<NeighborRow[]>;
12
+ writeSummary(_repoId: string, _id: string, _fields: SummaryFields): Promise<WriteSummaryResult>;
13
+ federatedRepoIds(): Promise<string[]>;
14
+ runRead(): Promise<Record<string, unknown>[]>;
15
+ close(): Promise<void>;
16
+ }
@@ -0,0 +1,36 @@
1
+ const MSG = "Neo4j not configured: set NEO4J_PASSWORD and run `docker compose up` in indexer/";
2
+ /** A no-op store used when NEO4J_PASSWORD is absent.
3
+ * All operations reject with an instructive error. */
4
+ export class UnconfiguredStore {
5
+ async getNode(_repoIds, _id) {
6
+ throw new Error(MSG);
7
+ }
8
+ async resolveByPathAndName() {
9
+ throw new Error(MSG);
10
+ }
11
+ async resolveByName() {
12
+ throw new Error(MSG);
13
+ }
14
+ async callers() {
15
+ throw new Error(MSG);
16
+ }
17
+ async callees() {
18
+ throw new Error(MSG);
19
+ }
20
+ async calleesAt2Hops() {
21
+ throw new Error(MSG);
22
+ }
23
+ async writeSummary(_repoId, _id, _fields) {
24
+ throw new Error(MSG);
25
+ }
26
+ async federatedRepoIds() {
27
+ throw new Error(MSG);
28
+ }
29
+ async runRead() {
30
+ throw new Error(MSG);
31
+ }
32
+ async close() {
33
+ // nothing to close
34
+ }
35
+ }
36
+ //# sourceMappingURL=UnconfiguredStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"UnconfiguredStore.js","sourceRoot":"","sources":["../../src/store/UnconfiguredStore.ts"],"names":[],"mappings":"AAQA,MAAM,GAAG,GACP,kFAAkF,CAAC;AAErF;uDACuD;AACvD,MAAM,OAAO,iBAAiB;IAC5B,KAAK,CAAC,OAAO,CAAC,QAAkB,EAAE,GAAW;QAC3C,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,oBAAoB;QACxB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,cAAc;QAClB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,YAAY,CAChB,OAAe,EACf,GAAW,EACX,OAAsB;QAEtB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,gBAAgB;QACpB,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,KAAK,CAAC,KAAK;QACT,mBAAmB;IACrB,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { GraphStore } from "./GraphStore.js";
2
+ /** The active repo_id plus all transitively federated repo_ids (sorted, deduped).
3
+ * Direct children resolve via committed root→proxy edges; grandchildren via the
4
+ * stitch edges created at load. Cached ~30s per repo. */
5
+ export declare function federationIds(store: GraphStore, repoId: string): Promise<string[]>;
6
+ /** Clears the federation cache. Exported for test isolation (the cache is a
7
+ * process-global with a 30s TTL; functionally fine for the single-store MCP
8
+ * server, but tests that reuse a repo_id within the window need a reset). */
9
+ export declare function clearFederationCache(): void;
@@ -0,0 +1,29 @@
1
+ const TTL_MS = 30_000;
2
+ const cache = new Map();
3
+ /** The active repo_id plus all transitively federated repo_ids (sorted, deduped).
4
+ * Direct children resolve via committed root→proxy edges; grandchildren via the
5
+ * stitch edges created at load. Cached ~30s per repo. */
6
+ export async function federationIds(store, repoId) {
7
+ const hit = cache.get(repoId);
8
+ if (hit && Date.now() - hit.at < TTL_MS)
9
+ return hit.ids;
10
+ let ids = new Set([repoId]);
11
+ try {
12
+ for (const id of await store.federatedRepoIds(repoId))
13
+ ids.add(id);
14
+ }
15
+ catch {
16
+ // Degrade to the single repo on any error (never break a read).
17
+ ids = new Set([repoId]);
18
+ }
19
+ const sorted = [...ids].sort();
20
+ cache.set(repoId, { ids: sorted, at: Date.now() });
21
+ return sorted;
22
+ }
23
+ /** Clears the federation cache. Exported for test isolation (the cache is a
24
+ * process-global with a 30s TTL; functionally fine for the single-store MCP
25
+ * server, but tests that reuse a repo_id within the window need a reset). */
26
+ export function clearFederationCache() {
27
+ cache.clear();
28
+ }
29
+ //# sourceMappingURL=federation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"federation.js","sourceRoot":"","sources":["../../src/store/federation.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG,MAAM,CAAC;AACtB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyC,CAAC;AAE/D;;0DAE0D;AAC1D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAiB,EAAE,MAAc;IACnE,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC;IACxD,IAAI,GAAG,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,KAAK,MAAM,EAAE,IAAI,MAAM,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;QAChE,GAAG,GAAG,IAAI,GAAG,CAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/B,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;8EAE8E;AAC9E,MAAM,UAAU,oBAAoB;IAClC,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,43 @@
1
+ /** Parses committed RepoSkein JSONL into in-memory records + lookup indices.
2
+ * Pure (no I/O) so it is trivially testable. Committed JSONL has no repo_id
3
+ * property — the repo is supplied by the caller (which .reposkein/ was loaded). */
4
+ export interface ParsedNode {
5
+ id: string;
6
+ repoId: string;
7
+ labels: string[];
8
+ props: Record<string, unknown>;
9
+ }
10
+ export interface ParsedEdge {
11
+ from: string;
12
+ type: string;
13
+ to: string;
14
+ props: Record<string, unknown>;
15
+ }
16
+ export interface ParsedGraph {
17
+ byId: Map<string, ParsedNode>;
18
+ /** CALLS edges only, grouped by source id. */
19
+ callsFrom: Map<string, ParsedEdge[]>;
20
+ /** CALLS edges only, grouped by target id. */
21
+ callsTo: Map<string, ParsedEdge[]>;
22
+ nodes: ParsedNode[];
23
+ edges: ParsedEdge[];
24
+ }
25
+ export declare function parseNodes(text: string, repoId: string): ParsedNode[];
26
+ export declare function parseEdges(text: string): ParsedEdge[];
27
+ /** Builds lookup indices from parsed node/edge text. */
28
+ export declare function buildGraph(nodesText: string, edgesText: string, repoId: string): ParsedGraph;
29
+ /** An empty graph (used when .reposkein files are missing). */
30
+ export declare function emptyGraph(): ParsedGraph;
31
+ export interface RepoSource {
32
+ repoId: string;
33
+ nodesText: string;
34
+ edgesText: string;
35
+ }
36
+ /** Builds one merged graph from several repos' committed JSONL, then injects
37
+ * DB-only-style cross-repo edges (M3 + M4):
38
+ * - IMPORTS edges (File→File) from external_import_targets (parity with Neo4j
39
+ * stitch_cross_repo_imports).
40
+ * - CALLS edges (Function→Function) from external_calls, import-scoped first
41
+ * (confidence 0.6) with federation-wide unique fallback (0.5); ambiguous
42
+ * skipped. Per-name (mirrors Neo4j stitch_cross_repo_calls). */
43
+ export declare function buildFederatedGraph(repos: RepoSource[]): ParsedGraph;