@danielblomma/cortex-mcp 2.4.0 → 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.
Files changed (214) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/README.md +24 -3
  3. package/bin/cli/arguments.mjs +60 -0
  4. package/bin/cli/context-passthrough.mjs +129 -0
  5. package/bin/cli/daemon.mjs +157 -0
  6. package/bin/cli/enterprise.mjs +516 -0
  7. package/bin/cli/help.mjs +88 -0
  8. package/bin/cli/hooks.mjs +199 -0
  9. package/bin/cli/mcp-command.mjs +87 -0
  10. package/bin/cli/paths.mjs +14 -0
  11. package/bin/cli/process.mjs +49 -0
  12. package/bin/cli/project-commands.mjs +237 -0
  13. package/bin/cli/project-runtime.mjs +34 -0
  14. package/bin/cli/query-command.mjs +18 -0
  15. package/bin/cli/router.mjs +66 -0
  16. package/bin/cli/run-command.mjs +44 -0
  17. package/bin/cli/scaffold-ownership.mjs +936 -0
  18. package/bin/cli/scaffold.mjs +687 -0
  19. package/bin/cli/stage-command.mjs +9 -0
  20. package/bin/cli/telemetry-command.mjs +18 -0
  21. package/bin/cli/trusted-runtime.mjs +18 -0
  22. package/bin/cortex.mjs +12 -1607
  23. package/bin/daemon-control.mjs +162 -0
  24. package/mcp-registry-submission.json +1 -1
  25. package/package.json +8 -3
  26. package/scaffold/mcp/dist/.cortex-build-hash +1 -0
  27. package/scaffold/mcp/dist/cli/enterprise-setup.js +134 -0
  28. package/scaffold/mcp/dist/cli/govern.js +937 -0
  29. package/scaffold/mcp/dist/cli/query.js +409 -0
  30. package/scaffold/mcp/dist/cli/run.js +295 -0
  31. package/scaffold/mcp/dist/cli/stage.js +308 -0
  32. package/scaffold/mcp/dist/cli/telemetry-test.js +141 -0
  33. package/scaffold/mcp/dist/cli/ungoverned-detector.js +133 -0
  34. package/scaffold/mcp/dist/contextEntities.js +282 -0
  35. package/scaffold/mcp/dist/core/audit/query.js +72 -0
  36. package/scaffold/mcp/dist/core/audit/writer.js +28 -0
  37. package/scaffold/mcp/dist/core/config.js +235 -0
  38. package/scaffold/mcp/dist/core/enterprise-host-identity.js +193 -0
  39. package/scaffold/mcp/dist/core/enterprise-identity.js +18 -0
  40. package/scaffold/mcp/dist/core/enterprise-rotation.js +158 -0
  41. package/scaffold/mcp/dist/core/govern-paths.js +21 -0
  42. package/scaffold/mcp/dist/core/index.js +14 -0
  43. package/scaffold/mcp/dist/core/license.js +278 -0
  44. package/scaffold/mcp/dist/core/policy/enforce.js +66 -0
  45. package/scaffold/mcp/dist/core/policy/injection.js +172 -0
  46. package/scaffold/mcp/dist/core/policy/store.js +179 -0
  47. package/scaffold/mcp/dist/core/rbac/check.js +30 -0
  48. package/scaffold/mcp/dist/core/secure-endpoint.js +25 -0
  49. package/scaffold/mcp/dist/core/telemetry/collector.js +285 -0
  50. package/scaffold/mcp/dist/core/telemetry/state-dir.js +31 -0
  51. package/scaffold/mcp/dist/core/validators/builtins.js +632 -0
  52. package/scaffold/mcp/dist/core/validators/config.js +44 -0
  53. package/scaffold/mcp/dist/core/validators/engine.js +120 -0
  54. package/scaffold/mcp/dist/core/validators/evaluators/code_comments.js +236 -0
  55. package/scaffold/mcp/dist/core/validators/evaluators/regex.js +116 -0
  56. package/scaffold/mcp/dist/core/workflow/artifact-io.js +103 -0
  57. package/scaffold/mcp/dist/core/workflow/capabilities.js +88 -0
  58. package/scaffold/mcp/dist/core/workflow/default-workflows.js +102 -0
  59. package/scaffold/mcp/dist/core/workflow/enforcement.js +164 -0
  60. package/scaffold/mcp/dist/core/workflow/envelope.js +132 -0
  61. package/scaffold/mcp/dist/core/workflow/index.js +11 -0
  62. package/scaffold/mcp/dist/core/workflow/mcp-tools.js +175 -0
  63. package/scaffold/mcp/dist/core/workflow/resolution.js +69 -0
  64. package/scaffold/mcp/dist/core/workflow/run-lifecycle.js +123 -0
  65. package/scaffold/mcp/dist/core/workflow/schemas.js +141 -0
  66. package/scaffold/mcp/dist/core/workflow/synced-capability-registry.js +60 -0
  67. package/scaffold/mcp/dist/core/workflow/synced-registry.js +60 -0
  68. package/scaffold/mcp/dist/daemon/capability-sync-checker.js +242 -0
  69. package/scaffold/mcp/dist/daemon/client.js +130 -0
  70. package/scaffold/mcp/dist/daemon/egress-proxy.js +288 -0
  71. package/scaffold/mcp/dist/daemon/global-host-events.js +222 -0
  72. package/scaffold/mcp/dist/daemon/heartbeat-pusher.js +116 -0
  73. package/scaffold/mcp/dist/daemon/heartbeat-tracker.js +165 -0
  74. package/scaffold/mcp/dist/daemon/host-events-pusher.js +249 -0
  75. package/scaffold/mcp/dist/daemon/main.js +449 -0
  76. package/scaffold/mcp/dist/daemon/paths.js +36 -0
  77. package/scaffold/mcp/dist/daemon/project-service-registry.js +78 -0
  78. package/scaffold/mcp/dist/daemon/protocol.js +8 -0
  79. package/scaffold/mcp/dist/daemon/server.js +180 -0
  80. package/scaffold/mcp/dist/daemon/skill-sync-checker.js +557 -0
  81. package/scaffold/mcp/dist/daemon/sync-checker.js +165 -0
  82. package/scaffold/mcp/dist/daemon/ungoverned-scanner.js +136 -0
  83. package/scaffold/mcp/dist/daemon/workflow-sync-checker.js +249 -0
  84. package/scaffold/mcp/dist/defaults.js +6 -0
  85. package/scaffold/mcp/dist/embed.js +627 -0
  86. package/scaffold/mcp/dist/embedScheduler.js +479 -0
  87. package/scaffold/mcp/dist/embeddings.js +167 -0
  88. package/scaffold/mcp/dist/enterprise/audit/push.js +66 -0
  89. package/scaffold/mcp/dist/enterprise/index.js +327 -0
  90. package/scaffold/mcp/dist/enterprise/model/deploy.js +27 -0
  91. package/scaffold/mcp/dist/enterprise/policy/sync.js +129 -0
  92. package/scaffold/mcp/dist/enterprise/privacy/boundary.js +184 -0
  93. package/scaffold/mcp/dist/enterprise/reviews/changed-files.js +33 -0
  94. package/scaffold/mcp/dist/enterprise/reviews/pattern-context.js +202 -0
  95. package/scaffold/mcp/dist/enterprise/reviews/policy-selection.js +46 -0
  96. package/scaffold/mcp/dist/enterprise/reviews/push.js +102 -0
  97. package/scaffold/mcp/dist/enterprise/reviews/trust-state.js +186 -0
  98. package/scaffold/mcp/dist/enterprise/telemetry/sync.js +57 -0
  99. package/scaffold/mcp/dist/enterprise/tools/enterprise.js +826 -0
  100. package/scaffold/mcp/dist/enterprise/tools/harness.js +40 -0
  101. package/scaffold/mcp/dist/enterprise/tools/walk.js +73 -0
  102. package/scaffold/mcp/dist/enterprise/violations/push.js +77 -0
  103. package/scaffold/mcp/dist/enterprise/workflow/push.js +44 -0
  104. package/scaffold/mcp/dist/enterprise/workflow/state.js +329 -0
  105. package/scaffold/mcp/dist/frontmatter.js +33 -0
  106. package/scaffold/mcp/dist/graph.js +769 -0
  107. package/scaffold/mcp/dist/graphCsv.js +55 -0
  108. package/scaffold/mcp/dist/graphMetrics.js +8 -0
  109. package/scaffold/mcp/dist/hooks/permission-request.js +89 -0
  110. package/scaffold/mcp/dist/hooks/post-tool-use.js +105 -0
  111. package/scaffold/mcp/dist/hooks/pre-compact.js +29 -0
  112. package/scaffold/mcp/dist/hooks/pre-tool-use.js +78 -0
  113. package/scaffold/mcp/dist/hooks/session-end.js +43 -0
  114. package/scaffold/mcp/dist/hooks/session-start.js +41 -0
  115. package/scaffold/mcp/dist/hooks/shared.js +194 -0
  116. package/scaffold/mcp/dist/hooks/stop.js +28 -0
  117. package/scaffold/mcp/dist/hooks/user-prompt-submit.js +33 -0
  118. package/scaffold/mcp/dist/impactPresentation.js +137 -0
  119. package/scaffold/mcp/dist/impactRanking.js +191 -0
  120. package/scaffold/mcp/dist/impactResponse.js +30 -0
  121. package/scaffold/mcp/dist/impactResults.js +105 -0
  122. package/scaffold/mcp/dist/impactSeed.js +20 -0
  123. package/scaffold/mcp/dist/impactTraversal.js +64 -0
  124. package/scaffold/mcp/dist/jsonl.js +77 -0
  125. package/scaffold/mcp/dist/loadGraph.js +759 -0
  126. package/scaffold/mcp/dist/lruCache.js +38 -0
  127. package/scaffold/mcp/dist/paths.js +97 -0
  128. package/scaffold/mcp/dist/patternEvidence.js +272 -0
  129. package/scaffold/mcp/dist/plugin.js +81 -0
  130. package/scaffold/mcp/dist/presets.js +78 -0
  131. package/scaffold/mcp/dist/relatedResponse.js +18 -0
  132. package/scaffold/mcp/dist/relatedTraversal.js +78 -0
  133. package/scaffold/mcp/dist/rules.js +23 -0
  134. package/scaffold/mcp/dist/search.js +212 -0
  135. package/scaffold/mcp/dist/searchCore.js +457 -0
  136. package/scaffold/mcp/dist/searchResults.js +230 -0
  137. package/scaffold/mcp/dist/server.js +317 -0
  138. package/scaffold/mcp/dist/types.js +1 -0
  139. package/scaffold/mcp/package-lock.json +321 -200
  140. package/scaffold/mcp/package.json +15 -6
  141. package/scaffold/mcp/src/cli/enterprise-setup.ts +82 -8
  142. package/scaffold/mcp/src/cli/govern.ts +137 -52
  143. package/scaffold/mcp/src/cli/run.ts +53 -19
  144. package/scaffold/mcp/src/cli/stage.ts +8 -3
  145. package/scaffold/mcp/src/core/config.ts +9 -2
  146. package/scaffold/mcp/src/core/enterprise-host-identity.ts +259 -0
  147. package/scaffold/mcp/src/core/enterprise-identity.ts +20 -0
  148. package/scaffold/mcp/src/core/enterprise-rotation.ts +185 -0
  149. package/scaffold/mcp/src/core/govern-paths.ts +30 -0
  150. package/scaffold/mcp/src/core/license.ts +186 -17
  151. package/scaffold/mcp/src/core/secure-endpoint.ts +23 -0
  152. package/scaffold/mcp/src/core/workflow/enforcement.ts +8 -1
  153. package/scaffold/mcp/src/core/workflow/mcp-tools.ts +3 -0
  154. package/scaffold/mcp/src/core/workflow/resolution.ts +9 -1
  155. package/scaffold/mcp/src/core/workflow/synced-capability-registry.ts +15 -0
  156. package/scaffold/mcp/src/core/workflow/synced-registry.ts +15 -0
  157. package/scaffold/mcp/src/daemon/capability-sync-checker.ts +38 -2
  158. package/scaffold/mcp/src/daemon/egress-proxy.ts +14 -8
  159. package/scaffold/mcp/src/daemon/global-host-events.ts +288 -0
  160. package/scaffold/mcp/src/daemon/heartbeat-pusher.ts +4 -0
  161. package/scaffold/mcp/src/daemon/heartbeat-tracker.ts +2 -0
  162. package/scaffold/mcp/src/daemon/host-events-pusher.ts +5 -0
  163. package/scaffold/mcp/src/daemon/main.ts +99 -25
  164. package/scaffold/mcp/src/daemon/project-service-registry.ts +107 -0
  165. package/scaffold/mcp/src/daemon/skill-sync-checker.ts +368 -31
  166. package/scaffold/mcp/src/daemon/sync-checker.ts +4 -0
  167. package/scaffold/mcp/src/daemon/ungoverned-scanner.ts +57 -25
  168. package/scaffold/mcp/src/daemon/workflow-sync-checker.ts +41 -2
  169. package/scaffold/mcp/src/enterprise/audit/push.ts +8 -0
  170. package/scaffold/mcp/src/enterprise/policy/sync.ts +12 -0
  171. package/scaffold/mcp/src/enterprise/reviews/push.ts +9 -0
  172. package/scaffold/mcp/src/enterprise/reviews/trust-state.ts +3 -1
  173. package/scaffold/mcp/src/enterprise/telemetry/sync.ts +9 -0
  174. package/scaffold/mcp/src/enterprise/violations/push.ts +9 -0
  175. package/scaffold/mcp/src/enterprise/workflow/push.ts +7 -0
  176. package/scaffold/mcp/src/plugin.ts +20 -0
  177. package/scaffold/mcp/tests/copilot-shim.test.mjs +19 -1
  178. package/scaffold/mcp/tests/egress-proxy.test.mjs +37 -0
  179. package/scaffold/mcp/tests/enterprise-identity-sync.test.mjs +401 -0
  180. package/scaffold/mcp/tests/enterprise-setup.test.mjs +189 -0
  181. package/scaffold/mcp/tests/global-host-events.test.mjs +81 -0
  182. package/scaffold/mcp/tests/govern-install.test.mjs +95 -2
  183. package/scaffold/mcp/tests/govern-repair.test.mjs +20 -3
  184. package/scaffold/mcp/tests/heartbeat-tracker.test.mjs +26 -0
  185. package/scaffold/mcp/tests/license.test.mjs +367 -0
  186. package/scaffold/mcp/tests/project-service-registry.test.mjs +172 -0
  187. package/scaffold/mcp/tests/review-trust-contract.test.mjs +18 -0
  188. package/scaffold/mcp/tests/secure-enterprise-endpoint.test.mjs +46 -0
  189. package/scaffold/mcp/tests/skill-sync-checker.test.mjs +446 -2
  190. package/scaffold/mcp/tests/ungoverned-scanner.test.mjs +104 -22
  191. package/scaffold/mcp/tests/workflow-cli.test.mjs +14 -1
  192. package/scaffold/mcp/tests/workflow-synced-capabilities.test.mjs +37 -0
  193. package/scaffold/mcp/tests/workflow-synced-registry.test.mjs +40 -1
  194. package/scaffold/ownership/baseline-v2.4.1.json +22 -0
  195. package/scaffold/ownership/current.json +4 -0
  196. package/scaffold/ownership/v1.json +456 -0
  197. package/scaffold/scripts/ingest-parsers.mjs +1 -387
  198. package/scaffold/scripts/ingest-worker.mjs +4 -1
  199. package/scaffold/scripts/ingest.mjs +5 -3899
  200. package/scaffold/scripts/lib/ingest/arguments.mjs +78 -0
  201. package/scaffold/scripts/lib/ingest/chunks.mjs +212 -0
  202. package/scaffold/scripts/lib/ingest/config.mjs +120 -0
  203. package/scaffold/scripts/lib/ingest/constants.mjs +222 -0
  204. package/scaffold/scripts/lib/ingest/files.mjs +387 -0
  205. package/scaffold/scripts/lib/ingest/incremental-state.mjs +131 -0
  206. package/scaffold/scripts/lib/ingest/io.mjs +78 -0
  207. package/scaffold/scripts/lib/ingest/main.mjs +76 -0
  208. package/scaffold/scripts/lib/ingest/parser-composition.mjs +140 -0
  209. package/scaffold/scripts/lib/ingest/parser-registry.mjs +387 -0
  210. package/scaffold/scripts/lib/ingest/pipeline-stages.mjs +1625 -0
  211. package/scaffold/scripts/lib/ingest/projects.mjs +272 -0
  212. package/scaffold/scripts/lib/ingest/relations.mjs +860 -0
  213. package/scaffold/scripts/lib/ingest/runtime-paths.mjs +11 -0
  214. 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
+ }