@mrc2204/agent-smart-memo 5.0.2 → 5.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 +209 -375
- package/bin/asm.mjs +365 -0
- package/bin/opencode-mcp-server.mjs +320 -0
- package/dist/core/contracts/adapter-contracts.d.ts +1 -1
- package/dist/core/contracts/adapter-contracts.d.ts.map +1 -1
- package/dist/core/contracts/change-overlay-contracts.d.ts +69 -0
- package/dist/core/contracts/change-overlay-contracts.d.ts.map +1 -0
- package/dist/core/contracts/change-overlay-contracts.js +2 -0
- package/dist/core/contracts/change-overlay-contracts.js.map +1 -0
- package/dist/core/contracts/feature-pack-contracts.d.ts +37 -0
- package/dist/core/contracts/feature-pack-contracts.d.ts.map +1 -0
- package/dist/core/contracts/feature-pack-contracts.js +8 -0
- package/dist/core/contracts/feature-pack-contracts.js.map +1 -0
- package/dist/core/contracts/project-query-contracts.d.ts +84 -0
- package/dist/core/contracts/project-query-contracts.d.ts.map +1 -0
- package/dist/core/contracts/project-query-contracts.js +2 -0
- package/dist/core/contracts/project-query-contracts.js.map +1 -0
- package/dist/core/graph/code-graph-model.d.ts +9 -0
- package/dist/core/graph/code-graph-model.d.ts.map +1 -0
- package/dist/core/graph/code-graph-model.js +70 -0
- package/dist/core/graph/code-graph-model.js.map +1 -0
- package/dist/core/graph/code-graph-populator.d.ts +20 -0
- package/dist/core/graph/code-graph-populator.d.ts.map +1 -0
- package/dist/core/graph/code-graph-populator.js +760 -0
- package/dist/core/graph/code-graph-populator.js.map +1 -0
- package/dist/core/graph/contracts.d.ts +29 -0
- package/dist/core/graph/contracts.d.ts.map +1 -0
- package/dist/core/graph/contracts.js +47 -0
- package/dist/core/graph/contracts.js.map +1 -0
- package/dist/core/ingest/contracts.d.ts +44 -0
- package/dist/core/ingest/contracts.d.ts.map +1 -0
- package/dist/core/ingest/contracts.js +2 -0
- package/dist/core/ingest/contracts.js.map +1 -0
- package/dist/core/ingest/ids.d.ts +5 -0
- package/dist/core/ingest/ids.d.ts.map +1 -0
- package/dist/core/ingest/ids.js +17 -0
- package/dist/core/ingest/ids.js.map +1 -0
- package/dist/core/ingest/ingest-pipeline.d.ts +4 -0
- package/dist/core/ingest/ingest-pipeline.d.ts.map +1 -0
- package/dist/core/ingest/ingest-pipeline.js +105 -0
- package/dist/core/ingest/ingest-pipeline.js.map +1 -0
- package/dist/core/ingest/semantic-block-extractor.d.ts +9 -0
- package/dist/core/ingest/semantic-block-extractor.d.ts.map +1 -0
- package/dist/core/ingest/semantic-block-extractor.js +171 -0
- package/dist/core/ingest/semantic-block-extractor.js.map +1 -0
- package/dist/core/usecases/default-memory-usecase-port.d.ts +38 -0
- package/dist/core/usecases/default-memory-usecase-port.d.ts.map +1 -1
- package/dist/core/usecases/default-memory-usecase-port.js +1686 -12
- package/dist/core/usecases/default-memory-usecase-port.js.map +1 -1
- package/dist/db/graph-db.d.ts +24 -0
- package/dist/db/graph-db.d.ts.map +1 -1
- package/dist/db/graph-db.js +81 -2
- package/dist/db/graph-db.js.map +1 -1
- package/dist/db/slot-db.d.ts +235 -2
- package/dist/db/slot-db.d.ts.map +1 -1
- package/dist/db/slot-db.js +840 -18
- package/dist/db/slot-db.js.map +1 -1
- package/dist/index.d.ts +7 -247
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -119
- package/dist/index.js.map +1 -1
- package/dist/shared/asm-config.d.ts +82 -0
- package/dist/shared/asm-config.d.ts.map +1 -0
- package/dist/shared/asm-config.js +254 -0
- package/dist/shared/asm-config.js.map +1 -0
- package/dist/shared/slotdb-path.d.ts +4 -3
- package/dist/shared/slotdb-path.d.ts.map +1 -1
- package/dist/shared/slotdb-path.js +15 -6
- package/dist/shared/slotdb-path.js.map +1 -1
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +131 -0
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/project-tools.d.ts.map +1 -1
- package/dist/tools/project-tools.js +543 -0
- package/dist/tools/project-tools.js.map +1 -1
- package/openclaw.plugin.json +5 -164
- package/package.json +61 -26
- package/scripts/init-openclaw.mjs +727 -0
|
@@ -0,0 +1,760 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { dirname, extname, join, normalize } from "node:path";
|
|
3
|
+
import { extractSemanticBlocks } from "../ingest/semantic-block-extractor.js";
|
|
4
|
+
import { upsertUniversalGraphNode, upsertUniversalGraphRelation, } from "./code-graph-model.js";
|
|
5
|
+
const ADAPTER_KIND = "indexer.code_graph.populate";
|
|
6
|
+
export function buildCodeGraphFileNodeId(projectId, relativePath) {
|
|
7
|
+
return `file:${projectId}:${normalizePath(relativePath)}`;
|
|
8
|
+
}
|
|
9
|
+
export function buildCodeGraphModuleNodeId(projectId, moduleName) {
|
|
10
|
+
return `module:${projectId}:${String(moduleName || "").trim()}`;
|
|
11
|
+
}
|
|
12
|
+
export function buildCodeGraphSymbolNodeId(projectId, relativePath, semanticPath) {
|
|
13
|
+
return `symbol:${projectId}:${normalizePath(relativePath)}:${semanticPath}`;
|
|
14
|
+
}
|
|
15
|
+
function buildCodeGraphDependencyNodeId(specifier) {
|
|
16
|
+
return `module_dep:${String(specifier || "").trim()}`;
|
|
17
|
+
}
|
|
18
|
+
function buildCodeGraphDependencySymbolNodeId(specifier, symbolName) {
|
|
19
|
+
return `symbol_dep:${String(specifier || "").trim()}:${String(symbolName || "").trim()}`;
|
|
20
|
+
}
|
|
21
|
+
function buildCodeGraphRouteNodeId(projectId, routePath) {
|
|
22
|
+
return `route:${projectId}:${routePath}`;
|
|
23
|
+
}
|
|
24
|
+
function buildCodeGraphJobNodeId(projectId, jobKey) {
|
|
25
|
+
return `job:${projectId}:${sha1(jobKey)}`;
|
|
26
|
+
}
|
|
27
|
+
function buildCodeGraphEventNodeId(projectId, eventKey) {
|
|
28
|
+
return `event:${projectId}:${sha1(eventKey)}`;
|
|
29
|
+
}
|
|
30
|
+
function sha1(raw) {
|
|
31
|
+
return createHash("sha1").update(raw).digest("hex");
|
|
32
|
+
}
|
|
33
|
+
function normalizePath(input) {
|
|
34
|
+
return normalize(String(input || "").replace(/\\/g, "/")).replace(/^\.\//, "").replace(/\\/g, "/");
|
|
35
|
+
}
|
|
36
|
+
function parseImportedNames(clause) {
|
|
37
|
+
const names = new Set();
|
|
38
|
+
const cleaned = String(clause || "").trim();
|
|
39
|
+
if (!cleaned)
|
|
40
|
+
return [];
|
|
41
|
+
const namespaceMatch = cleaned.match(/\*\s+as\s+([A-Za-z_$][\w$]*)/);
|
|
42
|
+
if (namespaceMatch?.[1])
|
|
43
|
+
names.add(namespaceMatch[1]);
|
|
44
|
+
const namedGroup = cleaned.match(/\{([\s\S]*?)\}/);
|
|
45
|
+
if (namedGroup?.[1]) {
|
|
46
|
+
for (const tokenRaw of namedGroup[1].split(",")) {
|
|
47
|
+
const token = tokenRaw.trim();
|
|
48
|
+
if (!token)
|
|
49
|
+
continue;
|
|
50
|
+
const alias = token.match(/\bas\s+([A-Za-z_$][\w$]*)$/i);
|
|
51
|
+
if (alias?.[1]) {
|
|
52
|
+
names.add(alias[1]);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
const bare = token.match(/^([A-Za-z_$][\w$]*)$/);
|
|
56
|
+
if (bare?.[1])
|
|
57
|
+
names.add(bare[1]);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
const withoutBraces = cleaned.replace(/\{[\s\S]*?\}/g, "").trim();
|
|
62
|
+
if (withoutBraces) {
|
|
63
|
+
for (const tokenRaw of withoutBraces.split(",")) {
|
|
64
|
+
const token = tokenRaw.trim();
|
|
65
|
+
if (!token || token.startsWith("*"))
|
|
66
|
+
continue;
|
|
67
|
+
const defaultMatch = token.match(/^([A-Za-z_$][\w$]*)$/);
|
|
68
|
+
if (defaultMatch?.[1])
|
|
69
|
+
names.add(defaultMatch[1]);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return Array.from(names);
|
|
73
|
+
}
|
|
74
|
+
function parseImportStatements(content) {
|
|
75
|
+
const out = [];
|
|
76
|
+
const importFrom = /^\s*import\s+([\s\S]*?)\s+from\s*["'`]([^"'`]+)["'`]/gm;
|
|
77
|
+
const importOnly = /^\s*import\s*["'`]([^"'`]+)["'`]/gm;
|
|
78
|
+
const requireExpr = /^\s*(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\(\s*["'`]([^"'`]+)["'`]\s*\)/gm;
|
|
79
|
+
let match;
|
|
80
|
+
while ((match = importFrom.exec(content))) {
|
|
81
|
+
out.push({
|
|
82
|
+
specifier: match[2],
|
|
83
|
+
importedNames: parseImportedNames(match[1]),
|
|
84
|
+
line: lineOf(content, match.index),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
while ((match = importOnly.exec(content))) {
|
|
88
|
+
out.push({
|
|
89
|
+
specifier: match[1],
|
|
90
|
+
importedNames: [],
|
|
91
|
+
line: lineOf(content, match.index),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
while ((match = requireExpr.exec(content))) {
|
|
95
|
+
out.push({
|
|
96
|
+
specifier: match[2],
|
|
97
|
+
importedNames: [match[1]],
|
|
98
|
+
line: lineOf(content, match.index),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const dedup = new Map();
|
|
102
|
+
for (const item of out) {
|
|
103
|
+
const key = `${item.specifier}@@${item.line}`;
|
|
104
|
+
const existing = dedup.get(key);
|
|
105
|
+
if (!existing) {
|
|
106
|
+
dedup.set(key, item);
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const names = new Set([...existing.importedNames, ...item.importedNames]);
|
|
110
|
+
dedup.set(key, { ...existing, importedNames: Array.from(names) });
|
|
111
|
+
}
|
|
112
|
+
return Array.from(dedup.values()).sort((a, b) => a.line - b.line);
|
|
113
|
+
}
|
|
114
|
+
function resolveRelativeImportPath(sourceRelativePath, specifier) {
|
|
115
|
+
const baseDir = dirname(sourceRelativePath);
|
|
116
|
+
const candidate = normalizePath(join(baseDir, specifier));
|
|
117
|
+
if (extname(candidate))
|
|
118
|
+
return candidate;
|
|
119
|
+
return `${candidate}.ts`;
|
|
120
|
+
}
|
|
121
|
+
function extractCallTargets(blockText) {
|
|
122
|
+
const callRegex = /\b([A-Za-z_][A-Za-z0-9_]*)\s*\(/g;
|
|
123
|
+
const banned = new Set([
|
|
124
|
+
"if",
|
|
125
|
+
"for",
|
|
126
|
+
"while",
|
|
127
|
+
"switch",
|
|
128
|
+
"catch",
|
|
129
|
+
"return",
|
|
130
|
+
"new",
|
|
131
|
+
"function",
|
|
132
|
+
"class",
|
|
133
|
+
"setTimeout",
|
|
134
|
+
"setInterval",
|
|
135
|
+
"Promise",
|
|
136
|
+
"console",
|
|
137
|
+
"require",
|
|
138
|
+
]);
|
|
139
|
+
const out = new Set();
|
|
140
|
+
let match;
|
|
141
|
+
while ((match = callRegex.exec(blockText))) {
|
|
142
|
+
const name = match[1];
|
|
143
|
+
if (!banned.has(name))
|
|
144
|
+
out.add(name);
|
|
145
|
+
}
|
|
146
|
+
return Array.from(out);
|
|
147
|
+
}
|
|
148
|
+
function normalizeRoutePath(routePath) {
|
|
149
|
+
const normalized = String(routePath || "").trim();
|
|
150
|
+
if (!normalized)
|
|
151
|
+
return "/";
|
|
152
|
+
const cleaned = normalized.replace(/\/+/g, "/");
|
|
153
|
+
if (cleaned.startsWith("/"))
|
|
154
|
+
return cleaned;
|
|
155
|
+
return `/${cleaned}`;
|
|
156
|
+
}
|
|
157
|
+
function joinRoutePath(prefix, childPath) {
|
|
158
|
+
const base = normalizeRoutePath(prefix);
|
|
159
|
+
const child = String(childPath || "").trim();
|
|
160
|
+
if (!child || child === "/")
|
|
161
|
+
return base;
|
|
162
|
+
const normalizedChild = child.startsWith("/") ? child : `/${child}`;
|
|
163
|
+
const joined = `${base.replace(/\/$/, "")}${normalizedChild}`;
|
|
164
|
+
return normalizeRoutePath(joined);
|
|
165
|
+
}
|
|
166
|
+
function extractRouteMatches(text) {
|
|
167
|
+
const out = [];
|
|
168
|
+
const push = (path, offset) => {
|
|
169
|
+
const normalized = normalizeRoutePath(path);
|
|
170
|
+
out.push({ path: normalized, line: lineOf(text, offset) });
|
|
171
|
+
};
|
|
172
|
+
const httpRoutes = /\.(?:get|post|put|patch|delete|all|options|head)\s*\(\s*["'`]([^"'`]+)["'`]/gi;
|
|
173
|
+
const nestController = /@Controller\s*\(\s*(?:["'`]([^"'`]*)["'`])?\s*\)/g;
|
|
174
|
+
const nestRoutes = /@(?:Get|Post|Put|Patch|Delete|All|Options|Head)\s*\(\s*(?:["'`]([^"'`]*)["'`])?\s*\)/g;
|
|
175
|
+
let match;
|
|
176
|
+
while ((match = httpRoutes.exec(text))) {
|
|
177
|
+
push(match[1], match.index);
|
|
178
|
+
}
|
|
179
|
+
const controllerPrefixes = [];
|
|
180
|
+
while ((match = nestController.exec(text))) {
|
|
181
|
+
controllerPrefixes.push({
|
|
182
|
+
offset: match.index,
|
|
183
|
+
prefix: normalizeRoutePath(match[1] || "/"),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
while ((match = nestRoutes.exec(text))) {
|
|
187
|
+
const routeOffset = match.index;
|
|
188
|
+
const methodPath = String(match[1] || "").trim();
|
|
189
|
+
const controllerPrefix = [...controllerPrefixes]
|
|
190
|
+
.reverse()
|
|
191
|
+
.find((item) => item.offset <= routeOffset)?.prefix;
|
|
192
|
+
if (controllerPrefix) {
|
|
193
|
+
push(joinRoutePath(controllerPrefix, methodPath), routeOffset);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (methodPath) {
|
|
197
|
+
push(methodPath, routeOffset);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
const dedup = new Map();
|
|
201
|
+
for (const item of out) {
|
|
202
|
+
const existing = dedup.get(item.path);
|
|
203
|
+
if (!existing || item.line < existing.line)
|
|
204
|
+
dedup.set(item.path, item);
|
|
205
|
+
}
|
|
206
|
+
return Array.from(dedup.values()).sort((a, b) => a.line - b.line || a.path.localeCompare(b.path));
|
|
207
|
+
}
|
|
208
|
+
function extractScheduleMatches(text) {
|
|
209
|
+
const out = [];
|
|
210
|
+
const cronSchedule = /\bcron\.schedule\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
211
|
+
const scheduleJob = /\bscheduleJob\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
212
|
+
const setIntervalRegex = /\bsetInterval\s*\([^,]+,\s*(\d+)\s*\)/g;
|
|
213
|
+
const setTimeoutRegex = /\bsetTimeout\s*\([^,]+,\s*(\d+)\s*\)/g;
|
|
214
|
+
const nestCron = /@Cron\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
215
|
+
const nestInterval = /@Interval\s*\(\s*(\d+)\s*\)/g;
|
|
216
|
+
const nestTimeout = /@Timeout\s*\(\s*(\d+)\s*\)/g;
|
|
217
|
+
const bullProcess = /@Process\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
218
|
+
const agendaEvery = /\bagenda\.every\s*\(\s*["'`]([^"'`]+)["'`]/g;
|
|
219
|
+
let match;
|
|
220
|
+
while ((match = cronSchedule.exec(text)))
|
|
221
|
+
out.push({ path: `cron:${match[1]}`, line: lineOf(text, match.index) });
|
|
222
|
+
while ((match = scheduleJob.exec(text)))
|
|
223
|
+
out.push({ path: `scheduleJob:${match[1]}`, line: lineOf(text, match.index) });
|
|
224
|
+
while ((match = setIntervalRegex.exec(text)))
|
|
225
|
+
out.push({ path: `interval:${match[1]}ms`, line: lineOf(text, match.index) });
|
|
226
|
+
while ((match = setTimeoutRegex.exec(text)))
|
|
227
|
+
out.push({ path: `timeout:${match[1]}ms`, line: lineOf(text, match.index) });
|
|
228
|
+
while ((match = nestCron.exec(text)))
|
|
229
|
+
out.push({ path: `cron:${match[1]}`, line: lineOf(text, match.index) });
|
|
230
|
+
while ((match = nestInterval.exec(text)))
|
|
231
|
+
out.push({ path: `interval:${match[1]}ms`, line: lineOf(text, match.index) });
|
|
232
|
+
while ((match = nestTimeout.exec(text)))
|
|
233
|
+
out.push({ path: `timeout:${match[1]}ms`, line: lineOf(text, match.index) });
|
|
234
|
+
while ((match = bullProcess.exec(text)))
|
|
235
|
+
out.push({ path: `queue:${match[1]}`, line: lineOf(text, match.index) });
|
|
236
|
+
while ((match = agendaEvery.exec(text)))
|
|
237
|
+
out.push({ path: `agenda:${match[1]}`, line: lineOf(text, match.index) });
|
|
238
|
+
const dedup = new Map();
|
|
239
|
+
for (const item of out) {
|
|
240
|
+
const existing = dedup.get(item.path);
|
|
241
|
+
if (!existing || item.line < existing.line)
|
|
242
|
+
dedup.set(item.path, item);
|
|
243
|
+
}
|
|
244
|
+
return Array.from(dedup.values()).sort((a, b) => a.line - b.line || a.path.localeCompare(b.path));
|
|
245
|
+
}
|
|
246
|
+
function extractEventSignals(text) {
|
|
247
|
+
const emits = [];
|
|
248
|
+
const consumes = [];
|
|
249
|
+
const emitPatterns = [
|
|
250
|
+
/\.emit\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
251
|
+
/\.publish\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
252
|
+
/@Emit\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
253
|
+
/dispatchEvent\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
254
|
+
];
|
|
255
|
+
const consumePatterns = [
|
|
256
|
+
/\.on\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
257
|
+
/\.once\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
258
|
+
/\.subscribe\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
259
|
+
/@On(?:Event)?\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
260
|
+
/@EventPattern\s*\(\s*["'`]([^"'`]+)["'`]/g,
|
|
261
|
+
];
|
|
262
|
+
for (const pattern of emitPatterns) {
|
|
263
|
+
let match;
|
|
264
|
+
while ((match = pattern.exec(text))) {
|
|
265
|
+
emits.push({ eventKey: String(match[1]), line: lineOf(text, match.index) });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
for (const pattern of consumePatterns) {
|
|
269
|
+
let match;
|
|
270
|
+
while ((match = pattern.exec(text))) {
|
|
271
|
+
consumes.push({ eventKey: String(match[1]), line: lineOf(text, match.index) });
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const dedup = (items) => {
|
|
275
|
+
const map = new Map();
|
|
276
|
+
for (const item of items) {
|
|
277
|
+
const key = item.eventKey;
|
|
278
|
+
const existing = map.get(key);
|
|
279
|
+
if (!existing || item.line < existing.line)
|
|
280
|
+
map.set(key, item);
|
|
281
|
+
}
|
|
282
|
+
return Array.from(map.values()).sort((a, b) => a.line - b.line || a.eventKey.localeCompare(b.eventKey));
|
|
283
|
+
};
|
|
284
|
+
return {
|
|
285
|
+
emits: dedup(emits),
|
|
286
|
+
consumes: dedup(consumes),
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function lineOf(content, offset) {
|
|
290
|
+
return content.slice(0, offset).split("\n").length;
|
|
291
|
+
}
|
|
292
|
+
export function populateUniversalCodeGraphForFile(graph, scopeUserId, scopeAgentId, input) {
|
|
293
|
+
const relativePath = normalizePath(input.relativePath);
|
|
294
|
+
const language = String(input.language || "").trim() || extname(relativePath).replace(/^\./, "") || "text";
|
|
295
|
+
const moduleName = String(input.module || "").trim() || null;
|
|
296
|
+
const content = String(input.content || "");
|
|
297
|
+
const blocks = Array.isArray(input.blocks) && input.blocks.length > 0
|
|
298
|
+
? input.blocks
|
|
299
|
+
: extractSemanticBlocks({ relativePath, content });
|
|
300
|
+
const relationTypeCounts = {
|
|
301
|
+
defines: 0,
|
|
302
|
+
imports: 0,
|
|
303
|
+
calls: 0,
|
|
304
|
+
routes_to: 0,
|
|
305
|
+
scheduled_as: 0,
|
|
306
|
+
depends_on: 0,
|
|
307
|
+
emits: 0,
|
|
308
|
+
consumes: 0,
|
|
309
|
+
};
|
|
310
|
+
let nodesUpserted = 0;
|
|
311
|
+
let relationsUpserted = 0;
|
|
312
|
+
const relationLocalKey = new Set();
|
|
313
|
+
const emitRelation = (key, emit, relationType) => {
|
|
314
|
+
if (relationLocalKey.has(key))
|
|
315
|
+
return;
|
|
316
|
+
emit();
|
|
317
|
+
relationLocalKey.add(key);
|
|
318
|
+
relationsUpserted += 1;
|
|
319
|
+
relationTypeCounts[relationType] += 1;
|
|
320
|
+
};
|
|
321
|
+
graph.deleteCodeAwareRelationshipsByEvidencePath(scopeUserId, scopeAgentId, relativePath);
|
|
322
|
+
const fileNodeId = buildCodeGraphFileNodeId(input.projectId, relativePath);
|
|
323
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
324
|
+
node_id: fileNodeId,
|
|
325
|
+
node_type: "file",
|
|
326
|
+
name: relativePath,
|
|
327
|
+
properties: {
|
|
328
|
+
project_id: input.projectId,
|
|
329
|
+
relative_path: relativePath,
|
|
330
|
+
module: moduleName,
|
|
331
|
+
language,
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
nodesUpserted += 1;
|
|
335
|
+
if (moduleName) {
|
|
336
|
+
const moduleNodeId = buildCodeGraphModuleNodeId(input.projectId, moduleName);
|
|
337
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
338
|
+
node_id: moduleNodeId,
|
|
339
|
+
node_type: "module",
|
|
340
|
+
name: moduleName,
|
|
341
|
+
properties: {
|
|
342
|
+
project_id: input.projectId,
|
|
343
|
+
module: moduleName,
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
nodesUpserted += 1;
|
|
347
|
+
emitRelation(`${moduleNodeId}|defines|${fileNodeId}`, () => {
|
|
348
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
349
|
+
source_node_id: moduleNodeId,
|
|
350
|
+
target_node_id: fileNodeId,
|
|
351
|
+
relation_type: "defines",
|
|
352
|
+
provenance: {
|
|
353
|
+
adapter_kind: ADAPTER_KIND,
|
|
354
|
+
confidence: 0.97,
|
|
355
|
+
evidence_path: relativePath,
|
|
356
|
+
},
|
|
357
|
+
properties: {
|
|
358
|
+
source_kind: "index_module",
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}, "defines");
|
|
362
|
+
}
|
|
363
|
+
const symbolBlocks = blocks.filter((block) => ["function", "class", "method", "tool"].includes(block.kind));
|
|
364
|
+
const symbolNodeIdsByName = new Map();
|
|
365
|
+
for (const block of symbolBlocks) {
|
|
366
|
+
const symbolName = String(block.symbol_name || "").trim();
|
|
367
|
+
if (!symbolName)
|
|
368
|
+
continue;
|
|
369
|
+
const symbolNodeId = buildCodeGraphSymbolNodeId(input.projectId, relativePath, block.semantic_path);
|
|
370
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
371
|
+
node_id: symbolNodeId,
|
|
372
|
+
node_type: "symbol",
|
|
373
|
+
name: symbolName,
|
|
374
|
+
properties: {
|
|
375
|
+
project_id: input.projectId,
|
|
376
|
+
relative_path: relativePath,
|
|
377
|
+
semantic_path: block.semantic_path,
|
|
378
|
+
symbol_kind: block.kind,
|
|
379
|
+
start_line: block.start_line,
|
|
380
|
+
end_line: block.end_line,
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
nodesUpserted += 1;
|
|
384
|
+
const prev = symbolNodeIdsByName.get(symbolName) || [];
|
|
385
|
+
prev.push(symbolNodeId);
|
|
386
|
+
symbolNodeIdsByName.set(symbolName, prev);
|
|
387
|
+
emitRelation(`${fileNodeId}|defines|${symbolNodeId}`, () => {
|
|
388
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
389
|
+
source_node_id: fileNodeId,
|
|
390
|
+
target_node_id: symbolNodeId,
|
|
391
|
+
relation_type: "defines",
|
|
392
|
+
provenance: {
|
|
393
|
+
adapter_kind: ADAPTER_KIND,
|
|
394
|
+
confidence: 0.99,
|
|
395
|
+
evidence_path: relativePath,
|
|
396
|
+
evidence_start_line: block.start_line,
|
|
397
|
+
evidence_end_line: block.end_line,
|
|
398
|
+
},
|
|
399
|
+
properties: {
|
|
400
|
+
symbol_kind: block.kind,
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
}, "defines");
|
|
404
|
+
}
|
|
405
|
+
const importedSymbolTargets = new Map();
|
|
406
|
+
const importStatements = parseImportStatements(content);
|
|
407
|
+
for (const importStmt of importStatements) {
|
|
408
|
+
const specifier = importStmt.specifier;
|
|
409
|
+
if (specifier.startsWith(".")) {
|
|
410
|
+
const targetPath = resolveRelativeImportPath(relativePath, specifier);
|
|
411
|
+
const importedFileNodeId = buildCodeGraphFileNodeId(input.projectId, targetPath);
|
|
412
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
413
|
+
node_id: importedFileNodeId,
|
|
414
|
+
node_type: "file",
|
|
415
|
+
name: targetPath,
|
|
416
|
+
properties: {
|
|
417
|
+
project_id: input.projectId,
|
|
418
|
+
relative_path: targetPath,
|
|
419
|
+
inferred: true,
|
|
420
|
+
},
|
|
421
|
+
});
|
|
422
|
+
nodesUpserted += 1;
|
|
423
|
+
for (const relationType of ["imports", "depends_on"]) {
|
|
424
|
+
emitRelation(`${fileNodeId}|${relationType}|${importedFileNodeId}`, () => {
|
|
425
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
426
|
+
source_node_id: fileNodeId,
|
|
427
|
+
target_node_id: importedFileNodeId,
|
|
428
|
+
relation_type: relationType,
|
|
429
|
+
provenance: {
|
|
430
|
+
adapter_kind: ADAPTER_KIND,
|
|
431
|
+
confidence: relationType === "imports" ? 0.95 : 0.88,
|
|
432
|
+
evidence_path: relativePath,
|
|
433
|
+
evidence_start_line: importStmt.line,
|
|
434
|
+
evidence_end_line: importStmt.line,
|
|
435
|
+
},
|
|
436
|
+
properties: {
|
|
437
|
+
specifier,
|
|
438
|
+
target_kind: "file",
|
|
439
|
+
},
|
|
440
|
+
});
|
|
441
|
+
}, relationType);
|
|
442
|
+
}
|
|
443
|
+
for (const importedName of importStmt.importedNames) {
|
|
444
|
+
const importedSymbolNodeId = buildCodeGraphSymbolNodeId(input.projectId, targetPath, `imported:${importedName}`);
|
|
445
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
446
|
+
node_id: importedSymbolNodeId,
|
|
447
|
+
node_type: "symbol",
|
|
448
|
+
name: importedName,
|
|
449
|
+
properties: {
|
|
450
|
+
project_id: input.projectId,
|
|
451
|
+
relative_path: targetPath,
|
|
452
|
+
semantic_path: `imported:${importedName}`,
|
|
453
|
+
inferred: true,
|
|
454
|
+
imported_by: relativePath,
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
nodesUpserted += 1;
|
|
458
|
+
emitRelation(`${importedFileNodeId}|defines|${importedSymbolNodeId}`, () => {
|
|
459
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
460
|
+
source_node_id: importedFileNodeId,
|
|
461
|
+
target_node_id: importedSymbolNodeId,
|
|
462
|
+
relation_type: "defines",
|
|
463
|
+
provenance: {
|
|
464
|
+
adapter_kind: ADAPTER_KIND,
|
|
465
|
+
confidence: 0.58,
|
|
466
|
+
evidence_path: relativePath,
|
|
467
|
+
evidence_start_line: importStmt.line,
|
|
468
|
+
evidence_end_line: importStmt.line,
|
|
469
|
+
},
|
|
470
|
+
properties: {
|
|
471
|
+
source_kind: "import_binding_inferred",
|
|
472
|
+
specifier,
|
|
473
|
+
},
|
|
474
|
+
});
|
|
475
|
+
}, "defines");
|
|
476
|
+
const prevTargets = importedSymbolTargets.get(importedName) || [];
|
|
477
|
+
prevTargets.push(importedSymbolNodeId);
|
|
478
|
+
importedSymbolTargets.set(importedName, prevTargets);
|
|
479
|
+
}
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
const dependencyNodeId = buildCodeGraphDependencyNodeId(specifier);
|
|
483
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
484
|
+
node_id: dependencyNodeId,
|
|
485
|
+
node_type: "module",
|
|
486
|
+
name: specifier,
|
|
487
|
+
properties: {
|
|
488
|
+
dependency: true,
|
|
489
|
+
},
|
|
490
|
+
});
|
|
491
|
+
nodesUpserted += 1;
|
|
492
|
+
for (const relationType of ["imports", "depends_on"]) {
|
|
493
|
+
emitRelation(`${fileNodeId}|${relationType}|${dependencyNodeId}`, () => {
|
|
494
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
495
|
+
source_node_id: fileNodeId,
|
|
496
|
+
target_node_id: dependencyNodeId,
|
|
497
|
+
relation_type: relationType,
|
|
498
|
+
provenance: {
|
|
499
|
+
adapter_kind: ADAPTER_KIND,
|
|
500
|
+
confidence: relationType === "imports" ? 0.93 : 0.9,
|
|
501
|
+
evidence_path: relativePath,
|
|
502
|
+
evidence_start_line: importStmt.line,
|
|
503
|
+
evidence_end_line: importStmt.line,
|
|
504
|
+
},
|
|
505
|
+
properties: {
|
|
506
|
+
specifier,
|
|
507
|
+
target_kind: "module",
|
|
508
|
+
},
|
|
509
|
+
});
|
|
510
|
+
}, relationType);
|
|
511
|
+
}
|
|
512
|
+
for (const importedName of importStmt.importedNames) {
|
|
513
|
+
const importedDepSymbolNodeId = buildCodeGraphDependencySymbolNodeId(specifier, importedName);
|
|
514
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
515
|
+
node_id: importedDepSymbolNodeId,
|
|
516
|
+
node_type: "symbol",
|
|
517
|
+
name: importedName,
|
|
518
|
+
properties: {
|
|
519
|
+
semantic_path: `module_import:${specifier}:${importedName}`,
|
|
520
|
+
inferred: true,
|
|
521
|
+
dependency_specifier: specifier,
|
|
522
|
+
imported_by: relativePath,
|
|
523
|
+
},
|
|
524
|
+
});
|
|
525
|
+
nodesUpserted += 1;
|
|
526
|
+
emitRelation(`${dependencyNodeId}|defines|${importedDepSymbolNodeId}`, () => {
|
|
527
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
528
|
+
source_node_id: dependencyNodeId,
|
|
529
|
+
target_node_id: importedDepSymbolNodeId,
|
|
530
|
+
relation_type: "defines",
|
|
531
|
+
provenance: {
|
|
532
|
+
adapter_kind: ADAPTER_KIND,
|
|
533
|
+
confidence: 0.5,
|
|
534
|
+
evidence_path: relativePath,
|
|
535
|
+
evidence_start_line: importStmt.line,
|
|
536
|
+
evidence_end_line: importStmt.line,
|
|
537
|
+
},
|
|
538
|
+
properties: {
|
|
539
|
+
source_kind: "dependency_binding_inferred",
|
|
540
|
+
specifier,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
}, "defines");
|
|
544
|
+
const prevTargets = importedSymbolTargets.get(importedName) || [];
|
|
545
|
+
prevTargets.push(importedDepSymbolNodeId);
|
|
546
|
+
importedSymbolTargets.set(importedName, prevTargets);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
for (const block of symbolBlocks) {
|
|
550
|
+
const sourceName = String(block.symbol_name || "").trim();
|
|
551
|
+
if (!sourceName)
|
|
552
|
+
continue;
|
|
553
|
+
const sourceNodeIds = symbolNodeIdsByName.get(sourceName) || [];
|
|
554
|
+
if (sourceNodeIds.length === 0)
|
|
555
|
+
continue;
|
|
556
|
+
const sourceNodeId = sourceNodeIds[0];
|
|
557
|
+
for (const targetName of extractCallTargets(block.text)) {
|
|
558
|
+
const localTargetNodeIds = symbolNodeIdsByName.get(targetName);
|
|
559
|
+
if (localTargetNodeIds && localTargetNodeIds.length > 0) {
|
|
560
|
+
for (const targetNodeId of localTargetNodeIds) {
|
|
561
|
+
if (targetNodeId === sourceNodeId)
|
|
562
|
+
continue;
|
|
563
|
+
emitRelation(`${sourceNodeId}|calls|${targetNodeId}`, () => {
|
|
564
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
565
|
+
source_node_id: sourceNodeId,
|
|
566
|
+
target_node_id: targetNodeId,
|
|
567
|
+
relation_type: "calls",
|
|
568
|
+
provenance: {
|
|
569
|
+
adapter_kind: ADAPTER_KIND,
|
|
570
|
+
confidence: 0.82,
|
|
571
|
+
evidence_path: relativePath,
|
|
572
|
+
evidence_start_line: block.start_line,
|
|
573
|
+
evidence_end_line: block.end_line,
|
|
574
|
+
},
|
|
575
|
+
properties: {
|
|
576
|
+
caller_symbol: sourceName,
|
|
577
|
+
callee_symbol: targetName,
|
|
578
|
+
},
|
|
579
|
+
});
|
|
580
|
+
}, "calls");
|
|
581
|
+
}
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
const importedTargets = importedSymbolTargets.get(targetName) || [];
|
|
585
|
+
for (const targetNodeId of importedTargets) {
|
|
586
|
+
emitRelation(`${sourceNodeId}|calls|${targetNodeId}`, () => {
|
|
587
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
588
|
+
source_node_id: sourceNodeId,
|
|
589
|
+
target_node_id: targetNodeId,
|
|
590
|
+
relation_type: "calls",
|
|
591
|
+
provenance: {
|
|
592
|
+
adapter_kind: ADAPTER_KIND,
|
|
593
|
+
confidence: 0.76,
|
|
594
|
+
evidence_path: relativePath,
|
|
595
|
+
evidence_start_line: block.start_line,
|
|
596
|
+
evidence_end_line: block.end_line,
|
|
597
|
+
},
|
|
598
|
+
properties: {
|
|
599
|
+
caller_symbol: sourceName,
|
|
600
|
+
callee_symbol: targetName,
|
|
601
|
+
target_kind: "imported_binding",
|
|
602
|
+
},
|
|
603
|
+
});
|
|
604
|
+
}, "calls");
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
const routePathToOwners = new Map();
|
|
609
|
+
for (const block of symbolBlocks) {
|
|
610
|
+
const sourceNodeId = buildCodeGraphSymbolNodeId(input.projectId, relativePath, block.semantic_path);
|
|
611
|
+
const routeMatches = extractRouteMatches(block.text);
|
|
612
|
+
for (const routeMatch of routeMatches) {
|
|
613
|
+
const owners = routePathToOwners.get(routeMatch.path) || [];
|
|
614
|
+
owners.push({ nodeId: sourceNodeId, line: block.start_line + Math.max(routeMatch.line - 1, 0) });
|
|
615
|
+
routePathToOwners.set(routeMatch.path, owners);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
const fileLevelRouteMatches = extractRouteMatches(content);
|
|
619
|
+
for (const routeMatch of fileLevelRouteMatches) {
|
|
620
|
+
const routeNodeId = buildCodeGraphRouteNodeId(input.projectId, routeMatch.path);
|
|
621
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
622
|
+
node_id: routeNodeId,
|
|
623
|
+
node_type: "route",
|
|
624
|
+
name: routeMatch.path,
|
|
625
|
+
properties: {
|
|
626
|
+
project_id: input.projectId,
|
|
627
|
+
route_path: routeMatch.path,
|
|
628
|
+
},
|
|
629
|
+
});
|
|
630
|
+
nodesUpserted += 1;
|
|
631
|
+
const owners = routePathToOwners.get(routeMatch.path) || [{ nodeId: fileNodeId, line: routeMatch.line }];
|
|
632
|
+
for (const owner of owners) {
|
|
633
|
+
emitRelation(`${owner.nodeId}|routes_to|${routeNodeId}`, () => {
|
|
634
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
635
|
+
source_node_id: owner.nodeId,
|
|
636
|
+
target_node_id: routeNodeId,
|
|
637
|
+
relation_type: "routes_to",
|
|
638
|
+
provenance: {
|
|
639
|
+
adapter_kind: ADAPTER_KIND,
|
|
640
|
+
confidence: owner.nodeId === fileNodeId ? 0.74 : 0.86,
|
|
641
|
+
evidence_path: relativePath,
|
|
642
|
+
evidence_start_line: owner.line,
|
|
643
|
+
evidence_end_line: owner.line,
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
}, "routes_to");
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
const scheduleKeyToOwners = new Map();
|
|
650
|
+
for (const block of symbolBlocks) {
|
|
651
|
+
const sourceNodeId = buildCodeGraphSymbolNodeId(input.projectId, relativePath, block.semantic_path);
|
|
652
|
+
const scheduleMatches = extractScheduleMatches(block.text);
|
|
653
|
+
for (const scheduleMatch of scheduleMatches) {
|
|
654
|
+
const owners = scheduleKeyToOwners.get(scheduleMatch.path) || [];
|
|
655
|
+
owners.push({ nodeId: sourceNodeId, line: block.start_line + Math.max(scheduleMatch.line - 1, 0) });
|
|
656
|
+
scheduleKeyToOwners.set(scheduleMatch.path, owners);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
const fileLevelScheduleMatches = extractScheduleMatches(content);
|
|
660
|
+
for (const scheduleMatch of fileLevelScheduleMatches) {
|
|
661
|
+
const scheduleKey = scheduleMatch.path;
|
|
662
|
+
const jobNodeId = buildCodeGraphJobNodeId(input.projectId, `${relativePath}:${scheduleKey}`);
|
|
663
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
664
|
+
node_id: jobNodeId,
|
|
665
|
+
node_type: "job",
|
|
666
|
+
name: scheduleKey,
|
|
667
|
+
properties: {
|
|
668
|
+
project_id: input.projectId,
|
|
669
|
+
schedule_key: scheduleKey,
|
|
670
|
+
},
|
|
671
|
+
});
|
|
672
|
+
nodesUpserted += 1;
|
|
673
|
+
const owners = scheduleKeyToOwners.get(scheduleKey) || [{ nodeId: fileNodeId, line: scheduleMatch.line }];
|
|
674
|
+
for (const owner of owners) {
|
|
675
|
+
emitRelation(`${owner.nodeId}|scheduled_as|${jobNodeId}`, () => {
|
|
676
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
677
|
+
source_node_id: owner.nodeId,
|
|
678
|
+
target_node_id: jobNodeId,
|
|
679
|
+
relation_type: "scheduled_as",
|
|
680
|
+
provenance: {
|
|
681
|
+
adapter_kind: ADAPTER_KIND,
|
|
682
|
+
confidence: owner.nodeId === fileNodeId ? 0.72 : 0.84,
|
|
683
|
+
evidence_path: relativePath,
|
|
684
|
+
evidence_start_line: owner.line,
|
|
685
|
+
evidence_end_line: owner.line,
|
|
686
|
+
},
|
|
687
|
+
});
|
|
688
|
+
}, "scheduled_as");
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
const eventSignalToOwners = new Map();
|
|
692
|
+
for (const block of symbolBlocks) {
|
|
693
|
+
const sourceNodeId = buildCodeGraphSymbolNodeId(input.projectId, relativePath, block.semantic_path);
|
|
694
|
+
const eventSignals = extractEventSignals(block.text);
|
|
695
|
+
for (const emitEvent of eventSignals.emits) {
|
|
696
|
+
const owners = eventSignalToOwners.get(emitEvent.eventKey) || [];
|
|
697
|
+
owners.push({
|
|
698
|
+
nodeId: sourceNodeId,
|
|
699
|
+
line: block.start_line + Math.max(emitEvent.line - 1, 0),
|
|
700
|
+
mode: "emits",
|
|
701
|
+
});
|
|
702
|
+
eventSignalToOwners.set(emitEvent.eventKey, owners);
|
|
703
|
+
}
|
|
704
|
+
for (const consumeEvent of eventSignals.consumes) {
|
|
705
|
+
const owners = eventSignalToOwners.get(consumeEvent.eventKey) || [];
|
|
706
|
+
owners.push({
|
|
707
|
+
nodeId: sourceNodeId,
|
|
708
|
+
line: block.start_line + Math.max(consumeEvent.line - 1, 0),
|
|
709
|
+
mode: "consumes",
|
|
710
|
+
});
|
|
711
|
+
eventSignalToOwners.set(consumeEvent.eventKey, owners);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const fileLevelEventSignals = extractEventSignals(content);
|
|
715
|
+
const fileLevelEvents = [
|
|
716
|
+
...fileLevelEventSignals.emits.map((item) => ({ ...item, mode: "emits" })),
|
|
717
|
+
...fileLevelEventSignals.consumes.map((item) => ({ ...item, mode: "consumes" })),
|
|
718
|
+
];
|
|
719
|
+
for (const eventSignal of fileLevelEvents) {
|
|
720
|
+
const eventNodeId = buildCodeGraphEventNodeId(input.projectId, eventSignal.eventKey);
|
|
721
|
+
upsertUniversalGraphNode(graph, scopeUserId, scopeAgentId, {
|
|
722
|
+
node_id: eventNodeId,
|
|
723
|
+
node_type: "event",
|
|
724
|
+
name: eventSignal.eventKey,
|
|
725
|
+
properties: {
|
|
726
|
+
project_id: input.projectId,
|
|
727
|
+
event_key: eventSignal.eventKey,
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
nodesUpserted += 1;
|
|
731
|
+
const owners = eventSignalToOwners.get(eventSignal.eventKey)
|
|
732
|
+
?.filter((owner) => owner.mode === eventSignal.mode)
|
|
733
|
+
|| [{ nodeId: fileNodeId, line: eventSignal.line, mode: eventSignal.mode }];
|
|
734
|
+
for (const owner of owners) {
|
|
735
|
+
emitRelation(`${owner.nodeId}|${owner.mode}|${eventNodeId}`, () => {
|
|
736
|
+
upsertUniversalGraphRelation(graph, scopeUserId, scopeAgentId, {
|
|
737
|
+
source_node_id: owner.nodeId,
|
|
738
|
+
target_node_id: eventNodeId,
|
|
739
|
+
relation_type: owner.mode,
|
|
740
|
+
provenance: {
|
|
741
|
+
adapter_kind: ADAPTER_KIND,
|
|
742
|
+
confidence: owner.nodeId === fileNodeId ? 0.7 : 0.82,
|
|
743
|
+
evidence_path: relativePath,
|
|
744
|
+
evidence_start_line: owner.line,
|
|
745
|
+
evidence_end_line: owner.line,
|
|
746
|
+
},
|
|
747
|
+
properties: {
|
|
748
|
+
event_key: eventSignal.eventKey,
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
}, owner.mode);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
return {
|
|
755
|
+
nodes_upserted: nodesUpserted,
|
|
756
|
+
relations_upserted: relationsUpserted,
|
|
757
|
+
relation_type_counts: relationTypeCounts,
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
//# sourceMappingURL=code-graph-populator.js.map
|