@danielblomma/cortex-mcp 2.4.1 → 2.4.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/CHANGELOG.md +25 -0
- package/README.md +5 -0
- package/bin/cli/arguments.mjs +60 -0
- package/bin/cli/context-passthrough.mjs +129 -0
- package/bin/cli/daemon.mjs +157 -0
- package/bin/cli/enterprise.mjs +516 -0
- package/bin/cli/help.mjs +88 -0
- package/bin/cli/hooks.mjs +199 -0
- package/bin/cli/mcp-command.mjs +87 -0
- package/bin/cli/paths.mjs +14 -0
- package/bin/cli/process.mjs +49 -0
- package/bin/cli/project-commands.mjs +237 -0
- package/bin/cli/project-runtime.mjs +34 -0
- package/bin/cli/query-command.mjs +18 -0
- package/bin/cli/router.mjs +66 -0
- package/bin/cli/run-command.mjs +44 -0
- package/bin/cli/scaffold-ownership.mjs +936 -0
- package/bin/cli/scaffold.mjs +687 -0
- package/bin/cli/stage-command.mjs +9 -0
- package/bin/cli/telemetry-command.mjs +18 -0
- package/bin/cli/trusted-runtime.mjs +18 -0
- package/bin/cortex.mjs +6 -1834
- package/mcp-registry-submission.json +1 -1
- package/package.json +3 -2
- package/scaffold/ownership/baseline-v2.4.1.json +22 -0
- package/scaffold/ownership/current.json +4 -0
- package/scaffold/ownership/v1.json +456 -0
- package/scaffold/scripts/ingest-parsers.mjs +1 -387
- package/scaffold/scripts/ingest-worker.mjs +4 -1
- package/scaffold/scripts/ingest.mjs +5 -3899
- package/scaffold/scripts/lib/ingest/arguments.mjs +78 -0
- package/scaffold/scripts/lib/ingest/chunks.mjs +212 -0
- package/scaffold/scripts/lib/ingest/config.mjs +120 -0
- package/scaffold/scripts/lib/ingest/constants.mjs +222 -0
- package/scaffold/scripts/lib/ingest/files.mjs +387 -0
- package/scaffold/scripts/lib/ingest/incremental-state.mjs +131 -0
- package/scaffold/scripts/lib/ingest/io.mjs +78 -0
- package/scaffold/scripts/lib/ingest/main.mjs +76 -0
- package/scaffold/scripts/lib/ingest/parser-composition.mjs +140 -0
- package/scaffold/scripts/lib/ingest/parser-registry.mjs +387 -0
- package/scaffold/scripts/lib/ingest/pipeline-stages.mjs +1625 -0
- package/scaffold/scripts/lib/ingest/projects.mjs +272 -0
- package/scaffold/scripts/lib/ingest/relations.mjs +860 -0
- package/scaffold/scripts/lib/ingest/runtime-paths.mjs +11 -0
- package/scaffold/scripts/lib/ingest/workers.mjs +264 -0
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { PROJECT_DEFINITION_EXTENSIONS } from "./constants.mjs";
|
|
3
|
+
import { toPosixPath } from "./files.mjs";
|
|
4
|
+
import {
|
|
5
|
+
decodeXmlEntities,
|
|
6
|
+
extractXmlTagValue,
|
|
7
|
+
relationKey
|
|
8
|
+
} from "./relations.mjs";
|
|
9
|
+
import { REPO_ROOT } from "./runtime-paths.mjs";
|
|
10
|
+
|
|
11
|
+
export function projectIdFor(filePath) {
|
|
12
|
+
return `project:${filePath}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function isProjectDefinitionFile(filePath) {
|
|
16
|
+
return PROJECT_DEFINITION_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function resolveProjectRelativePath(baseFilePath, includePath) {
|
|
20
|
+
if (!includePath) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const normalizedInclude = toPosixPath(decodeXmlEntities(includePath).trim().replace(/\\/g, "/"));
|
|
25
|
+
if (!normalizedInclude) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const resolved = path.resolve(REPO_ROOT, path.dirname(baseFilePath), normalizedInclude);
|
|
30
|
+
const relPath = toPosixPath(path.relative(REPO_ROOT, resolved));
|
|
31
|
+
if (!relPath || relPath.startsWith("../")) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return relPath;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function projectLanguageForExtension(ext) {
|
|
39
|
+
switch (ext) {
|
|
40
|
+
case ".vbproj":
|
|
41
|
+
return "vbnet";
|
|
42
|
+
case ".csproj":
|
|
43
|
+
return "csharp";
|
|
44
|
+
case ".fsproj":
|
|
45
|
+
return "fsharp";
|
|
46
|
+
case ".vcxproj":
|
|
47
|
+
return "cpp";
|
|
48
|
+
case ".sln":
|
|
49
|
+
return "solution";
|
|
50
|
+
default:
|
|
51
|
+
return "dotnet";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function collectXmlIncludeValues(content, elementNames) {
|
|
56
|
+
const values = [];
|
|
57
|
+
const pattern = new RegExp(
|
|
58
|
+
`<(?:${elementNames.join("|")})\\b[^>]*\\bInclude="([^"]+)"[^>]*\\/?>`,
|
|
59
|
+
"gi"
|
|
60
|
+
);
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
63
|
+
values.push(decodeXmlEntities(match[1]).trim());
|
|
64
|
+
}
|
|
65
|
+
return values;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function parseSolutionProject(fileRecord, indexedFileIds) {
|
|
69
|
+
const declaredMembers = [];
|
|
70
|
+
const referencesProjectRelations = [];
|
|
71
|
+
const includesFileRelations = [];
|
|
72
|
+
const fileRelationKeys = new Set();
|
|
73
|
+
const ext = path.extname(fileRecord.path).toLowerCase();
|
|
74
|
+
const fallbackName = path.basename(fileRecord.path, ext);
|
|
75
|
+
const projectPattern =
|
|
76
|
+
/^Project\([^)]*\)\s*=\s*"([^"]+)",\s*"([^"]+\.(?:vbproj|csproj|fsproj|vcxproj))",\s*"\{[^"]+\}"$/gim;
|
|
77
|
+
|
|
78
|
+
let match;
|
|
79
|
+
while ((match = projectPattern.exec(fileRecord.content)) !== null) {
|
|
80
|
+
const memberName = match[1].trim();
|
|
81
|
+
const memberPath = resolveProjectRelativePath(fileRecord.path, match[2]);
|
|
82
|
+
if (!memberPath) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
declaredMembers.push({ name: memberName, path: memberPath });
|
|
86
|
+
const targetId = projectIdFor(memberPath);
|
|
87
|
+
if (indexedFileIds.has(`file:${memberPath}`)) {
|
|
88
|
+
referencesProjectRelations.push({
|
|
89
|
+
from: projectIdFor(fileRecord.path),
|
|
90
|
+
to: targetId,
|
|
91
|
+
note: `solution_member:${memberName}`
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const fileId of [`file:${fileRecord.path}`]) {
|
|
97
|
+
if (indexedFileIds.has(fileId) && !fileRelationKeys.has(fileId)) {
|
|
98
|
+
fileRelationKeys.add(fileId);
|
|
99
|
+
includesFileRelations.push({ from: projectIdFor(fileRecord.path), to: fileId });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const summaryParts = [`Solution ${fallbackName}`];
|
|
104
|
+
if (declaredMembers.length > 0) {
|
|
105
|
+
summaryParts.push(`Contains ${declaredMembers.length} project references`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
project: {
|
|
110
|
+
id: projectIdFor(fileRecord.path),
|
|
111
|
+
path: fileRecord.path,
|
|
112
|
+
name: fallbackName,
|
|
113
|
+
kind: "solution",
|
|
114
|
+
language: projectLanguageForExtension(ext),
|
|
115
|
+
target_framework: "",
|
|
116
|
+
summary: `${summaryParts.join(". ")}.`,
|
|
117
|
+
file_count: includesFileRelations.length,
|
|
118
|
+
updated_at: fileRecord.updated_at,
|
|
119
|
+
source_of_truth: false,
|
|
120
|
+
trust_level: 78,
|
|
121
|
+
status: "active"
|
|
122
|
+
},
|
|
123
|
+
includesFileRelations,
|
|
124
|
+
referencesProjectRelations
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export function parseDotNetProject(fileRecord, indexedFileIds) {
|
|
128
|
+
const ext = path.extname(fileRecord.path).toLowerCase();
|
|
129
|
+
const fallbackName = path.basename(fileRecord.path, ext);
|
|
130
|
+
const assemblyName = extractXmlTagValue(fileRecord.content, "AssemblyName");
|
|
131
|
+
const rootNamespace = extractXmlTagValue(fileRecord.content, "RootNamespace");
|
|
132
|
+
const targetFrameworkRaw =
|
|
133
|
+
extractXmlTagValue(fileRecord.content, "TargetFramework") ||
|
|
134
|
+
extractXmlTagValue(fileRecord.content, "TargetFrameworkVersion") ||
|
|
135
|
+
extractXmlTagValue(fileRecord.content, "TargetFrameworks");
|
|
136
|
+
const targetFramework = targetFrameworkRaw.split(";")[0].trim();
|
|
137
|
+
const includeCandidates = collectXmlIncludeValues(fileRecord.content, [
|
|
138
|
+
"Compile",
|
|
139
|
+
"Content",
|
|
140
|
+
"EmbeddedResource",
|
|
141
|
+
"None",
|
|
142
|
+
"Page",
|
|
143
|
+
"ApplicationDefinition"
|
|
144
|
+
]);
|
|
145
|
+
const projectReferenceCandidates = collectXmlIncludeValues(fileRecord.content, ["ProjectReference"]);
|
|
146
|
+
const includesFileRelations = [];
|
|
147
|
+
const referencesProjectRelations = [];
|
|
148
|
+
const fileRelationKeys = new Set();
|
|
149
|
+
|
|
150
|
+
const addFileRelation = (relPath) => {
|
|
151
|
+
const fileId = `file:${relPath}`;
|
|
152
|
+
if (!indexedFileIds.has(fileId) || fileRelationKeys.has(fileId)) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
fileRelationKeys.add(fileId);
|
|
156
|
+
includesFileRelations.push({
|
|
157
|
+
from: projectIdFor(fileRecord.path),
|
|
158
|
+
to: fileId
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
addFileRelation(fileRecord.path);
|
|
163
|
+
|
|
164
|
+
for (const includePath of includeCandidates) {
|
|
165
|
+
const relPath = resolveProjectRelativePath(fileRecord.path, includePath);
|
|
166
|
+
if (!relPath) {
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
addFileRelation(relPath);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
for (const includePath of projectReferenceCandidates) {
|
|
173
|
+
const relPath = resolveProjectRelativePath(fileRecord.path, includePath);
|
|
174
|
+
if (!relPath) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const targetFileId = `file:${relPath}`;
|
|
178
|
+
if (!indexedFileIds.has(targetFileId)) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
referencesProjectRelations.push({
|
|
182
|
+
from: projectIdFor(fileRecord.path),
|
|
183
|
+
to: projectIdFor(relPath),
|
|
184
|
+
note: includePath
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const summaryParts = [
|
|
189
|
+
`${projectLanguageForExtension(ext).toUpperCase()} project ${assemblyName || rootNamespace || fallbackName}`
|
|
190
|
+
];
|
|
191
|
+
if (targetFramework) {
|
|
192
|
+
summaryParts.push(`Target framework ${targetFramework}`);
|
|
193
|
+
}
|
|
194
|
+
if (includesFileRelations.length > 1) {
|
|
195
|
+
summaryParts.push(`Includes ${includesFileRelations.length - 1} indexed project files`);
|
|
196
|
+
}
|
|
197
|
+
if (referencesProjectRelations.length > 0) {
|
|
198
|
+
summaryParts.push(`References ${referencesProjectRelations.length} projects`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
project: {
|
|
203
|
+
id: projectIdFor(fileRecord.path),
|
|
204
|
+
path: fileRecord.path,
|
|
205
|
+
name: assemblyName || rootNamespace || fallbackName,
|
|
206
|
+
kind: "project",
|
|
207
|
+
language: projectLanguageForExtension(ext),
|
|
208
|
+
target_framework: targetFramework,
|
|
209
|
+
summary: `${summaryParts.join(". ")}.`,
|
|
210
|
+
file_count: includesFileRelations.length,
|
|
211
|
+
updated_at: fileRecord.updated_at,
|
|
212
|
+
source_of_truth: false,
|
|
213
|
+
trust_level: 80,
|
|
214
|
+
status: "active"
|
|
215
|
+
},
|
|
216
|
+
includesFileRelations,
|
|
217
|
+
referencesProjectRelations
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function generateProjects(fileRecords) {
|
|
222
|
+
const indexedFileIds = new Set(fileRecords.map((record) => record.id));
|
|
223
|
+
const projectRecords = [];
|
|
224
|
+
const includesFileRelations = [];
|
|
225
|
+
const referencesProjectRelations = [];
|
|
226
|
+
const includeKeys = new Set();
|
|
227
|
+
const referenceKeys = new Set();
|
|
228
|
+
|
|
229
|
+
for (const fileRecord of fileRecords) {
|
|
230
|
+
if (!isProjectDefinitionFile(fileRecord.path)) {
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const ext = path.extname(fileRecord.path).toLowerCase();
|
|
235
|
+
const parsed =
|
|
236
|
+
ext === ".sln"
|
|
237
|
+
? parseSolutionProject(fileRecord, indexedFileIds)
|
|
238
|
+
: parseDotNetProject(fileRecord, indexedFileIds);
|
|
239
|
+
|
|
240
|
+
projectRecords.push(parsed.project);
|
|
241
|
+
|
|
242
|
+
for (const relation of parsed.includesFileRelations) {
|
|
243
|
+
const key = relationKey(relation.from, relation.to);
|
|
244
|
+
if (includeKeys.has(key)) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
includeKeys.add(key);
|
|
248
|
+
includesFileRelations.push(relation);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
for (const relation of parsed.referencesProjectRelations) {
|
|
252
|
+
const key = relationKey(relation.from, relation.to, relation.note);
|
|
253
|
+
if (referenceKeys.has(key)) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
referenceKeys.add(key);
|
|
257
|
+
referencesProjectRelations.push(relation);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
projectRecords.sort((a, b) => a.path.localeCompare(b.path));
|
|
262
|
+
includesFileRelations.sort((a, b) => relationKey(a.from, a.to).localeCompare(relationKey(b.from, b.to)));
|
|
263
|
+
referencesProjectRelations.sort((a, b) =>
|
|
264
|
+
relationKey(a.from, a.to, a.note).localeCompare(relationKey(b.from, b.to, b.note))
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
projects: projectRecords,
|
|
269
|
+
includesFileRelations,
|
|
270
|
+
referencesProjectRelations
|
|
271
|
+
};
|
|
272
|
+
}
|