@lzehrung/codegraph 2.1.1 → 2.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.
Files changed (254) hide show
  1. package/codegraph-skill/codegraph/SKILL.md +4 -5
  2. package/dist/agent/artifact.d.ts.map +1 -1
  3. package/dist/agent/artifact.js +105 -14
  4. package/dist/agent/artifact.js.map +1 -1
  5. package/dist/agent/explain.d.ts +3 -0
  6. package/dist/agent/explain.d.ts.map +1 -1
  7. package/dist/agent/explain.js +8 -0
  8. package/dist/agent/explain.js.map +1 -1
  9. package/dist/agent/explore.js +2 -0
  10. package/dist/agent/explore.js.map +1 -1
  11. package/dist/agent/orient.js +2 -0
  12. package/dist/agent/orient.js.map +1 -1
  13. package/dist/agent/packet.d.ts.map +1 -1
  14. package/dist/agent/packet.js +5 -12
  15. package/dist/agent/packet.js.map +1 -1
  16. package/dist/agent/query-index/content.d.ts +1 -1
  17. package/dist/agent/query-index/content.js +4 -4
  18. package/dist/agent/query-index/content.js.map +1 -1
  19. package/dist/agent/query-index/store.d.ts +3 -4
  20. package/dist/agent/query-index/store.d.ts.map +1 -1
  21. package/dist/agent/query-index/store.js +52 -18
  22. package/dist/agent/query-index/store.js.map +1 -1
  23. package/dist/agent/query-index/update.d.ts.map +1 -1
  24. package/dist/agent/query-index/update.js +24 -9
  25. package/dist/agent/query-index/update.js.map +1 -1
  26. package/dist/agent/renamePreview.d.ts.map +1 -1
  27. package/dist/agent/renamePreview.js +51 -2
  28. package/dist/agent/renamePreview.js.map +1 -1
  29. package/dist/agent/search.d.ts +3 -1
  30. package/dist/agent/search.d.ts.map +1 -1
  31. package/dist/agent/search.js +64 -18
  32. package/dist/agent/search.js.map +1 -1
  33. package/dist/agent/session.d.ts.map +1 -1
  34. package/dist/agent/session.js +1 -1
  35. package/dist/agent/session.js.map +1 -1
  36. package/dist/agent-tools.js +6 -6
  37. package/dist/agent-tools.js.map +1 -1
  38. package/dist/bin/cli.js +2762 -1508
  39. package/dist/bin/queryIndexWorker.js +84 -36
  40. package/dist/bin/rawQueryWorker.js +26 -2
  41. package/dist/cli/callHierarchy.d.ts.map +1 -1
  42. package/dist/cli/callHierarchy.js +9 -2
  43. package/dist/cli/callHierarchy.js.map +1 -1
  44. package/dist/cli/commandTable.js +1 -1
  45. package/dist/cli/commandTable.js.map +1 -1
  46. package/dist/cli/graph.d.ts.map +1 -1
  47. package/dist/cli/graph.js +52 -16
  48. package/dist/cli/graph.js.map +1 -1
  49. package/dist/cli/grep.d.ts +1 -1
  50. package/dist/cli/grep.d.ts.map +1 -1
  51. package/dist/cli/grep.js +14 -4
  52. package/dist/cli/grep.js.map +1 -1
  53. package/dist/cli/install.js +1 -1
  54. package/dist/cli/install.js.map +1 -1
  55. package/dist/cli/options.d.ts.map +1 -1
  56. package/dist/cli/options.js +23 -4
  57. package/dist/cli/options.js.map +1 -1
  58. package/dist/cli/renamePreview.d.ts.map +1 -1
  59. package/dist/cli/renamePreview.js +7 -1
  60. package/dist/cli/renamePreview.js.map +1 -1
  61. package/dist/cli/rootPolicy.d.ts.map +1 -1
  62. package/dist/cli/rootPolicy.js +36 -3
  63. package/dist/cli/rootPolicy.js.map +1 -1
  64. package/dist/cli/skill.js +1 -1
  65. package/dist/cli/skill.js.map +1 -1
  66. package/dist/cli/sql.js +1 -1
  67. package/dist/cli/symbols.d.ts.map +1 -1
  68. package/dist/cli/symbols.js +4 -2
  69. package/dist/cli/symbols.js.map +1 -1
  70. package/dist/cli.d.ts.map +1 -1
  71. package/dist/cli.js +36 -16
  72. package/dist/cli.js.map +1 -1
  73. package/dist/documentLinks/check.d.ts.map +1 -1
  74. package/dist/documentLinks/check.js +20 -9
  75. package/dist/documentLinks/check.js.map +1 -1
  76. package/dist/duplicates/types.d.ts +2 -0
  77. package/dist/duplicates/types.d.ts.map +1 -1
  78. package/dist/duplicates/units.d.ts.map +1 -1
  79. package/dist/duplicates/units.js +6 -2
  80. package/dist/duplicates/units.js.map +1 -1
  81. package/dist/duplicates.d.ts.map +1 -1
  82. package/dist/duplicates.js +59 -0
  83. package/dist/duplicates.js.map +1 -1
  84. package/dist/graphs/symbol-graph-detailed.d.ts +10 -1
  85. package/dist/graphs/symbol-graph-detailed.d.ts.map +1 -1
  86. package/dist/graphs/symbol-graph-detailed.js +18 -4
  87. package/dist/graphs/symbol-graph-detailed.js.map +1 -1
  88. package/dist/impact/analyzer.d.ts.map +1 -1
  89. package/dist/impact/analyzer.js +4 -1
  90. package/dist/impact/analyzer.js.map +1 -1
  91. package/dist/impact/budgets.d.ts.map +1 -1
  92. package/dist/impact/budgets.js +5 -3
  93. package/dist/impact/budgets.js.map +1 -1
  94. package/dist/impact/callCompatibility.d.ts +8 -1
  95. package/dist/impact/callCompatibility.d.ts.map +1 -1
  96. package/dist/impact/callCompatibility.js +55 -17
  97. package/dist/impact/callCompatibility.js.map +1 -1
  98. package/dist/impact/context.d.ts.map +1 -1
  99. package/dist/impact/context.js +4 -1
  100. package/dist/impact/context.js.map +1 -1
  101. package/dist/impact/direct.d.ts +1 -1
  102. package/dist/impact/direct.d.ts.map +1 -1
  103. package/dist/impact/parse.d.ts.map +1 -1
  104. package/dist/impact/parse.js +10 -1
  105. package/dist/impact/parse.js.map +1 -1
  106. package/dist/impact/report-suggestions.d.ts.map +1 -1
  107. package/dist/impact/report-suggestions.js +17 -11
  108. package/dist/impact/report-suggestions.js.map +1 -1
  109. package/dist/impact/report.d.ts.map +1 -1
  110. package/dist/impact/report.js +13 -2
  111. package/dist/impact/report.js.map +1 -1
  112. package/dist/impact/reportCompact.d.ts.map +1 -1
  113. package/dist/impact/reportCompact.js +1 -0
  114. package/dist/impact/reportCompact.js.map +1 -1
  115. package/dist/impact/reportFull.d.ts.map +1 -1
  116. package/dist/impact/reportFull.js +1 -0
  117. package/dist/impact/reportFull.js.map +1 -1
  118. package/dist/impact/reportParts.d.ts +9 -0
  119. package/dist/impact/reportParts.d.ts.map +1 -1
  120. package/dist/impact/severity.d.ts +3 -2
  121. package/dist/impact/severity.d.ts.map +1 -1
  122. package/dist/impact/severity.js +16 -5
  123. package/dist/impact/severity.js.map +1 -1
  124. package/dist/impact/streaming.d.ts.map +1 -1
  125. package/dist/impact/streaming.js +5 -5
  126. package/dist/impact/streaming.js.map +1 -1
  127. package/dist/impact/transitive.d.ts.map +1 -1
  128. package/dist/impact/transitive.js +13 -5
  129. package/dist/impact/transitive.js.map +1 -1
  130. package/dist/impact/types.d.ts +14 -0
  131. package/dist/impact/types.d.ts.map +1 -1
  132. package/dist/impact/types.js.map +1 -1
  133. package/dist/indexer/build-cache/manifest.d.ts +5 -3
  134. package/dist/indexer/build-cache/manifest.d.ts.map +1 -1
  135. package/dist/indexer/build-cache/manifest.js +122 -15
  136. package/dist/indexer/build-cache/manifest.js.map +1 -1
  137. package/dist/indexer/build-cache/module-cache.d.ts +1 -0
  138. package/dist/indexer/build-cache/module-cache.d.ts.map +1 -1
  139. package/dist/indexer/build-cache/module-cache.js +6 -0
  140. package/dist/indexer/build-cache/module-cache.js.map +1 -1
  141. package/dist/indexer/build-cache/project-snapshot.d.ts +7 -11
  142. package/dist/indexer/build-cache/project-snapshot.d.ts.map +1 -1
  143. package/dist/indexer/build-cache/project-snapshot.js +168 -76
  144. package/dist/indexer/build-cache/project-snapshot.js.map +1 -1
  145. package/dist/indexer/build-cache/resolver-environment.d.ts +2 -2
  146. package/dist/indexer/build-cache/resolver-environment.d.ts.map +1 -1
  147. package/dist/indexer/build-cache/resolver-environment.js +33 -6
  148. package/dist/indexer/build-cache/resolver-environment.js.map +1 -1
  149. package/dist/indexer/build-cache.d.ts +2 -2
  150. package/dist/indexer/build-cache.d.ts.map +1 -1
  151. package/dist/indexer/build-cache.js +2 -2
  152. package/dist/indexer/build-cache.js.map +1 -1
  153. package/dist/indexer/build-index.d.ts.map +1 -1
  154. package/dist/indexer/build-index.js +116 -51
  155. package/dist/indexer/build-index.js.map +1 -1
  156. package/dist/indexer/build-manifest.d.ts.map +1 -1
  157. package/dist/indexer/build-manifest.js +3 -0
  158. package/dist/indexer/build-manifest.js.map +1 -1
  159. package/dist/indexer/build-workers.d.ts +1 -1
  160. package/dist/indexer/build-workers.d.ts.map +1 -1
  161. package/dist/indexer/build-workers.js +57 -42
  162. package/dist/indexer/build-workers.js.map +1 -1
  163. package/dist/indexer/import-types.d.ts +8 -0
  164. package/dist/indexer/import-types.d.ts.map +1 -1
  165. package/dist/indexer/imports/python.d.ts.map +1 -1
  166. package/dist/indexer/imports/python.js +13 -8
  167. package/dist/indexer/imports/python.js.map +1 -1
  168. package/dist/indexer/incremental-plan.d.ts +2 -1
  169. package/dist/indexer/incremental-plan.d.ts.map +1 -1
  170. package/dist/indexer/incremental-plan.js +7 -4
  171. package/dist/indexer/incremental-plan.js.map +1 -1
  172. package/dist/indexer/locals-and-exports.d.ts.map +1 -1
  173. package/dist/indexer/locals-and-exports.js +25 -0
  174. package/dist/indexer/locals-and-exports.js.map +1 -1
  175. package/dist/indexer/navigation-references.d.ts.map +1 -1
  176. package/dist/indexer/navigation-references.js +7 -1
  177. package/dist/indexer/navigation-references.js.map +1 -1
  178. package/dist/indexer/navigation.d.ts.map +1 -1
  179. package/dist/indexer/navigation.js +10 -0
  180. package/dist/indexer/navigation.js.map +1 -1
  181. package/dist/indexer/parse-context.d.ts +1 -1
  182. package/dist/indexer/parse-context.d.ts.map +1 -1
  183. package/dist/indexer/parse-context.js +23 -2
  184. package/dist/indexer/parse-context.js.map +1 -1
  185. package/dist/indexer/types.d.ts +5 -1
  186. package/dist/indexer/types.d.ts.map +1 -1
  187. package/dist/installer/locks.d.ts.map +1 -1
  188. package/dist/installer/locks.js +1 -3
  189. package/dist/installer/locks.js.map +1 -1
  190. package/dist/installer/registry.d.ts.map +1 -1
  191. package/dist/installer/registry.js +62 -5
  192. package/dist/installer/registry.js.map +1 -1
  193. package/dist/mcp/server.d.ts +15 -0
  194. package/dist/mcp/server.d.ts.map +1 -1
  195. package/dist/mcp/server.js +126 -34
  196. package/dist/mcp/server.js.map +1 -1
  197. package/dist/mcp/tools.d.ts.map +1 -1
  198. package/dist/mcp/tools.js +8 -1
  199. package/dist/mcp/tools.js.map +1 -1
  200. package/dist/review/candidates.d.ts.map +1 -1
  201. package/dist/review/candidates.js +4 -1
  202. package/dist/review/candidates.js.map +1 -1
  203. package/dist/review/summaries.d.ts +5 -0
  204. package/dist/review/summaries.d.ts.map +1 -1
  205. package/dist/review/summaries.js +19 -11
  206. package/dist/review/summaries.js.map +1 -1
  207. package/dist/review/types.d.ts +3 -1
  208. package/dist/review/types.d.ts.map +1 -1
  209. package/dist/review/types.js +8 -1
  210. package/dist/review/types.js.map +1 -1
  211. package/dist/review.d.ts.map +1 -1
  212. package/dist/review.js +7 -3
  213. package/dist/review.js.map +1 -1
  214. package/dist/sqlite/schema.d.ts +2 -1
  215. package/dist/sqlite/schema.d.ts.map +1 -1
  216. package/dist/sqlite/schema.js +15 -1
  217. package/dist/sqlite/schema.js.map +1 -1
  218. package/dist/sqlite/write.d.ts.map +1 -1
  219. package/dist/sqlite/write.js +15 -0
  220. package/dist/sqlite/write.js.map +1 -1
  221. package/dist/sqlite-driver.d.ts +11 -0
  222. package/dist/sqlite-driver.d.ts.map +1 -1
  223. package/dist/sqlite-driver.js +27 -2
  224. package/dist/sqlite-driver.js.map +1 -1
  225. package/dist/util/concurrency.d.ts +1 -0
  226. package/dist/util/concurrency.d.ts.map +1 -1
  227. package/dist/util/concurrency.js +9 -2
  228. package/dist/util/concurrency.js.map +1 -1
  229. package/dist/util/confinedFile.d.ts +1 -0
  230. package/dist/util/confinedFile.d.ts.map +1 -1
  231. package/dist/util/confinedFile.js +17 -5
  232. package/dist/util/confinedFile.js.map +1 -1
  233. package/dist/util/errors.d.ts +2 -0
  234. package/dist/util/errors.d.ts.map +1 -1
  235. package/dist/util/errors.js +18 -0
  236. package/dist/util/errors.js.map +1 -1
  237. package/dist/util/git.d.ts.map +1 -1
  238. package/dist/util/git.js +72 -7
  239. package/dist/util/git.js.map +1 -1
  240. package/dist/util/paths.d.ts.map +1 -1
  241. package/dist/util/paths.js +45 -9
  242. package/dist/util/paths.js.map +1 -1
  243. package/dist/util/resolution/jvm.d.ts.map +1 -1
  244. package/dist/util/resolution/jvm.js +14 -8
  245. package/dist/util/resolution/jvm.js.map +1 -1
  246. package/dist/util/resolution/tsconfig.d.ts.map +1 -1
  247. package/dist/util/resolution/tsconfig.js +26 -12
  248. package/dist/util/resolution/tsconfig.js.map +1 -1
  249. package/dist/worker/nativeExtractWorker.d.ts +4 -2
  250. package/dist/worker/nativeExtractWorker.d.ts.map +1 -1
  251. package/dist/worker/nativeExtractWorker.js +12 -11
  252. package/dist/worker/nativeExtractWorker.js.map +1 -1
  253. package/docs/mcp.md +6 -4
  254. package/package.json +3 -3
@@ -4,12 +4,14 @@ import fsp from "node:fs/promises";
4
4
  import path from "node:path";
5
5
  import { performance } from "node:perf_hooks";
6
6
  import { languageExtensionPatterns, supportForFile } from "../languages.js";
7
+ import { isJsTsLanguage } from "../languages/js-family.js";
7
8
  import { loadWorkspaceConfig, resolveWorkspacePackage } from "../util/workspace.js";
8
9
  import { DEFAULT_PROJECT_PATTERNS, discoverProjectFiles, listProjectFiles, } from "../util/projectFiles.js";
9
10
  import { getGitHead, isGitRepo, getGitBlobHashes, listChangedFiles } from "../util/git.js";
10
- import { clearImportResolutionCaches, resolveSpecifier } from "../util/resolution.js";
11
+ import { clearResolutionCaches, resolveSpecifier } from "../util/resolution.js";
11
12
  import { assertFilePathWithinRoot, fileIdentityKey, initializeFileIdentityCaseSensitivity, isFilePathWithinRoot, normalizePath, } from "../util/paths.js";
12
13
  import { mapLimit } from "../util/concurrency.js";
14
+ import { readConfinedUtf8File } from "../util/confinedFile.js";
13
15
  import { resolveWorkerThreadCount } from "../util/workerThreads.js";
14
16
  import { logWithLevel } from "../logging.js";
15
17
  import { collectGraph } from "../graph-builder.js";
@@ -26,7 +28,7 @@ import { initNativeBackendReport } from "../native/nativeBackendReport.js";
26
28
  import { closeDuplicateUnitCacheDatabase } from "../duplicates.js";
27
29
  import { isNativeRequiredUnavailableError } from "../native/treeSitterNative.js";
28
30
  import { isNodeSqliteUnavailableError } from "../sqlite-driver.js";
29
- import { buildBloomFilterForFile, cacheSignatureForFile, closeDiskCacheDatabase, collectWorkspaceManifestDependencyEdges, computeConfigHash, createFallbackImportExtractionHandler, diffBuildOptions, fileSignature, graphOptionsEqual, initFileReport, initManifestReport, loadManifest, normalizeGraphOptions, normalizeIndexedFileInputs, normalizeLanguageExtensions, projectSnapshotFilesSignature, recordConfigHashResult, recordFileFailure, sanitizeManifestEntriesForRoot, sanitizeManifestTransientFilesForRoot, tryLoadFromCache, tryLoadPersistedBloomFilters, tryLoadProjectIndexSnapshot, tryLoadProjectSnapshotModules, verifyManifestEntries, writeModulesToCache, writeProjectIndexSnapshot, writeToCache, } from "./build-cache.js";
31
+ import { buildBloomFilterForFile, cacheSignatureForFile, closeDiskCacheDatabase, collectWorkspaceManifestDependencyEdges, computeConfigHash, createFallbackImportExtractionHandler, diffBuildOptions, fileSignature, fileSignatureFromSource, graphOptionsEqual, initFileReport, initManifestReport, loadManifest, normalizeGraphOptions, normalizeIndexedFileInputs, normalizeIndexedFileInputsWithinRoot, normalizeLanguageExtensions, projectSnapshotFilesSignature, recordConfigHashResult, recordFileFailure, sanitizeManifestEntriesForRoot, sanitizeManifestTransientFilesForRoot, tryLoadFromCache, tryLoadPersistedBloomFilters, tryLoadProjectIndexSnapshot, tryLoadProjectSnapshotModules, verifyManifestEntries, writeModulesToCache, writeProjectIndexSnapshot, writeToCache, } from "./build-cache.js";
30
32
  import { computeResolverEnvironmentFingerprint } from "./build-cache/resolver-environment.js";
31
33
  import { cacheRoot } from "./build-cache/location.js";
32
34
  import { SymbolKind, } from "./types.js";
@@ -36,7 +38,7 @@ import { buildSqlFactCache, buildSqlModuleIndex, sqlCorpusSignature } from "../s
36
38
  import { finalizeProjectIndex } from "./finalize.js";
37
39
  import { toManifestFileEntry, writeIndexManifestSnapshot } from "./build-manifest.js";
38
40
  import { prepareFileContextForBuild, setupWorkerPool, teardownWorkerPool, } from "./build-workers.js";
39
- import { buildIncrementalGitDiffOptions, canUseIncrementalDiscoveryFastPath, collectDeletedTrackedFileDependents, collectTrackedFileDependents, isMissingGitRevisionError, listUntrackedProjectFiles, partitionTrackedManifestFiles, probePathExistence, } from "./incremental-plan.js";
41
+ import { buildIncrementalGitDiffOptions, canUseIncrementalDiscoveryFastPath, buildTrackedFileReverseDependencies, collectDeletedTrackedFileDependents, collectTrackedFileDependents, isMissingGitRevisionError, listUntrackedProjectFiles, partitionTrackedManifestFiles, probePathExistence, } from "./incremental-plan.js";
40
42
  import { parsedCacheMaxEntries, setParsedCacheEntry } from "./parsed-cache.js";
41
43
  function initParserBackendDegradationReport(report) {
42
44
  if (!report)
@@ -75,13 +77,17 @@ function recordParserBackendDegradation(report, entry) {
75
77
  return;
76
78
  parserReport.files.push(entry);
77
79
  }
80
+ function isConfinedFileReadError(error) {
81
+ return (error instanceof Error &&
82
+ /outside project root|possible path confinement race|changed between verification and open|confined file target/u.test(error.message));
83
+ }
78
84
  function createEmptyModuleIndex(file) {
79
85
  return { file, exports: [], imports: [], locals: [] };
80
86
  }
81
87
  async function resolveCrossModuleSymbolExports(file, mod, support, projectRoot, graphOptions, workspaceConfig, logLevel) {
82
88
  if (!support.supportsCrossModuleSymbols)
83
89
  return;
84
- if (support.id !== "ts" && support.id !== "js")
90
+ if (!isJsTsLanguage(support.id))
85
91
  return;
86
92
  const { matchPath } = await import("../util/resolution.js").then((mod) => mod.loadNearestTsconfigFor(file, projectRoot, logLevel));
87
93
  for (const entry of mod.exports) {
@@ -107,11 +113,12 @@ async function resolveCrossModuleSymbolExports(file, mod, support, projectRoot,
107
113
  }
108
114
  }
109
115
  async function buildIndexedModuleForFile(args) {
110
- const prepared = await prepareFileContextForBuild(args.file, args.support, args.opts, args.workerSetup, args.report);
116
+ const prepared = await prepareFileContextForBuild(args.file, args.support, args.opts, args.workerSetup, args.report, args.confinedRoot, args.projectRoot, args.trustedSource);
111
117
  const { source, sup, nativeQueries, embeddedBlocks } = prepared;
112
118
  let resolvedLang = prepared.lang;
113
119
  let tree;
114
- const graphOnlyLanguage = isGraphOnlyLanguage(sup.id);
120
+ const graphOnlyLanguage = isGraphOnlyLanguage(sup.id), nativeSourceLimitFallback = prepared.nativeFallbackReason === "queryFailure" &&
121
+ !!prepared.nativeError?.startsWith("source exceeds native byte limit");
115
122
  if (prepared.syntaxTree) {
116
123
  const parsedTree = new ProjectedSyntaxTree(source, prepared.syntaxTree);
117
124
  tree = parsedTree;
@@ -124,7 +131,7 @@ async function buildIndexedModuleForFile(args) {
124
131
  nativeQueries,
125
132
  }, args.parsedCacheMaxEntries);
126
133
  }
127
- else if (!nativeQueries && !graphOnlyLanguage && sup.id !== "sql") {
134
+ else if (!nativeQueries && !graphOnlyLanguage && sup.id !== "sql" && !nativeSourceLimitFallback) {
128
135
  const parseAttempt = attemptParsePreparedFileContext(prepared);
129
136
  const parsed = parseAttempt.parsed;
130
137
  if (parsed) {
@@ -153,7 +160,7 @@ async function buildIndexedModuleForFile(args) {
153
160
  }
154
161
  }
155
162
  const lacksParserContext = !nativeQueries && !tree;
156
- if (args.bloomFilterCache) {
163
+ if (args.bloomFilterCache && !nativeSourceLimitFallback) {
157
164
  const filter = buildBloomFilterFromSource(source, sup);
158
165
  args.bloomFilterCache.set(args.file, filter);
159
166
  }
@@ -166,7 +173,7 @@ async function buildIndexedModuleForFile(args) {
166
173
  ...(args.opts?.languageExtensions ? { languageExtensions: args.opts.languageExtensions } : {}),
167
174
  ...(args.onFallbackImportExtraction ? { onFallbackImportExtraction: args.onFallbackImportExtraction } : {}),
168
175
  };
169
- const imports = sup.id === "sql"
176
+ const imports = nativeSourceLimitFallback || sup.id === "sql"
170
177
  ? []
171
178
  : await collectImportsForFile(args.file, args.projectRoot, {
172
179
  source,
@@ -362,9 +369,8 @@ function projectIndexManifestEntries(entries) {
362
369
  return new Map(Array.from(entries, ([file, entry]) => [file, toProjectIndexManifestEntry(entry)]));
363
370
  }
364
371
  function createIndexBuildRunState(projectRoot, opts, graphOptions = normalizeGraphOptions(opts?.graph)) {
365
- const report = opts?.report;
366
- if (report)
367
- initNativeBackendReport(report);
372
+ const report = opts?.report ?? { timings: {} };
373
+ initNativeBackendReport(report);
368
374
  const cacheMode = opts?.cache ?? "off";
369
375
  return {
370
376
  normalizedProjectRoot: normalizePath(path.resolve(projectRoot)),
@@ -399,6 +405,13 @@ function buildConcurrency(opts) {
399
405
  async function prepareFileSignatures(args) {
400
406
  const entries = await mapLimit(args.files, args.concurrency, async (file) => {
401
407
  const gitSig = args.gitSigMap.get(file);
408
+ const source = args.confinedRoot
409
+ ? await readConfinedUtf8File(args.confinedRoot, args.projectRoot, file)
410
+ : undefined;
411
+ if (source !== undefined) {
412
+ args.trustedSources?.set(file, source);
413
+ return [file, fileSignatureFromSource(source, gitSig)];
414
+ }
402
415
  const sigInfo = await fileSignature(file, args.needsContentHash ? args.opts?.cacheStrict : false, gitSig, {
403
416
  forceContentHash: args.cacheEnabled && !gitSig,
404
417
  });
@@ -410,7 +423,7 @@ async function buildProjectIndexFromExport(projectRoot, opts, helperOpts) {
410
423
  return buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpts);
411
424
  }
412
425
  async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperOpts) {
413
- clearImportResolutionCaches();
426
+ clearResolutionCaches();
414
427
  await initializeFileIdentityCaseSensitivity(projectRoot);
415
428
  const { normalizedProjectRoot, report, timings, totalStart, cacheMode, cacheEnabled, graphOptions, onFallbackImportExtraction, } = createIndexBuildRunState(projectRoot, opts);
416
429
  const manifestMode = helperOpts?.manifestMode ?? "off";
@@ -418,7 +431,11 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
418
431
  const shouldWriteManifest = manifestMode === "read-write";
419
432
  const projectFiles = helperOpts?.projectFiles;
420
433
  initManifestReport(report, useManifest, false);
421
- const normalizedFiles = Array.from(new Set(normalizeIndexedFileInputs(projectRoot, rawFiles ?? [], "Index file")));
434
+ const confinedRoot = helperOpts?.confineReads ? await fsp.realpath(projectRoot) : undefined;
435
+ const [trustedSources, normalizedFiles] = [
436
+ confinedRoot ? new Map() : undefined,
437
+ Array.from(new Set(normalizeIndexedFileInputs(projectRoot, rawFiles ?? [], "Index file"))),
438
+ ];
422
439
  if (!normalizedFiles.length && helperOpts?.warnNoFilesMessage) {
423
440
  logWithLevel(opts?.logLevel, "warn", helperOpts.warnNoFilesMessage);
424
441
  }
@@ -426,7 +443,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
426
443
  if (fileReport)
427
444
  fileReport.total = normalizedFiles.length;
428
445
  const manifestStart = performance.now();
429
- const manifest = useManifest && !helperOpts?.ignoreExistingManifest ? await loadManifest(projectRoot, opts) : null;
446
+ const manifest = useManifest && !helperOpts?.ignoreExistingManifest ? await loadManifest(projectRoot, opts, report) : null;
430
447
  const manifestFiles = sanitizeManifestEntriesForRoot(projectRoot, manifest?.files);
431
448
  const manifestOptionDiffs = manifest ? diffBuildOptions(manifest.buildOptions, opts) : [];
432
449
  const languageExtensionsChanged = manifestOptionDiffs.includes("languageExtensions");
@@ -468,10 +485,10 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
468
485
  graphOptionsEqual(manifest.graphOptions, graphOptions)
469
486
  ? new Map(Object.entries(manifestFiles).filter(([file]) => !staleCachedEdgeFiles.has(file)))
470
487
  : undefined;
488
+ const manifestEntries = shouldWriteManifest ? new Map() : undefined;
471
489
  if (report?.manifest) {
472
490
  report.manifest.reused = !!cachedGraphEntries;
473
491
  }
474
- const manifestEntries = shouldWriteManifest ? new Map() : undefined;
475
492
  const manifestEntriesForIndex = useManifest
476
493
  ? projectIndexManifestEntries(cachedGraphEntries ?? [])
477
494
  : new Map();
@@ -494,12 +511,14 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
494
511
  })
495
512
  .sort((left, right) => left.localeCompare(right));
496
513
  const fileSignatures = await prepareFileSignatures({
514
+ projectRoot,
497
515
  files: sqlFiles,
498
516
  opts,
499
517
  gitSigMap,
500
518
  cacheEnabled,
501
519
  needsContentHash: true,
502
520
  concurrency: conc,
521
+ ...(confinedRoot ? { confinedRoot, trustedSources } : {}),
503
522
  });
504
523
  const sqlCorpusSig = sqlCorpusSignature(sqlFiles, fileSignatures);
505
524
  let sqlFactCachePromise;
@@ -522,7 +541,9 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
522
541
  const bloomFilterCache = useBloomFilters
523
542
  ? new (await import("../util/bloomFilter.js")).BloomFilterCache()
524
543
  : undefined;
525
- const persistedBloomFilters = bloomFilterCache ? await tryLoadPersistedBloomFilters(projectRoot, opts) : null;
544
+ const persistedBloomFilters = bloomFilterCache
545
+ ? await tryLoadPersistedBloomFilters(projectRoot, opts, report)
546
+ : null;
526
547
  const parsedMap = new Map();
527
548
  const workspaceConfig = await loadWorkspaceConfig(projectRoot);
528
549
  const parseStart = performance.now();
@@ -549,9 +570,16 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
549
570
  let sigInfo = fileSignatures.get(file);
550
571
  if (!sigInfo) {
551
572
  const gitSig = gitSigMap.get(file);
552
- sigInfo = await fileSignature(file, opts?.cacheStrict, gitSig, {
553
- forceContentHash: cacheEnabled && !gitSig,
554
- });
573
+ const source = confinedRoot ? await readConfinedUtf8File(confinedRoot, projectRoot, file) : undefined;
574
+ if (source !== undefined) {
575
+ trustedSources?.set(file, source);
576
+ sigInfo = fileSignatureFromSource(source, gitSig);
577
+ }
578
+ else {
579
+ sigInfo = await fileSignature(file, opts?.cacheStrict, gitSig, {
580
+ forceContentHash: cacheEnabled && !gitSig,
581
+ });
582
+ }
555
583
  fileSignatures.set(file, sigInfo);
556
584
  }
557
585
  manifestEntriesForIndex.set(file, toProjectIndexManifestEntry(sigInfo));
@@ -638,6 +666,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
638
666
  onFallbackImportExtraction,
639
667
  fileSignatures,
640
668
  cacheEnabled,
669
+ ...(confinedRoot ? { confinedRoot, trustedSource: trustedSources?.get(file) } : {}),
641
670
  });
642
671
  mod = built.module;
643
672
  graphContext = built.graphContext;
@@ -672,6 +701,8 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
672
701
  catch (error) {
673
702
  if (isNativeRequiredUnavailableError(error) || isNodeSqliteUnavailableError(error))
674
703
  throw error;
704
+ if (isConfinedFileReadError(error))
705
+ throw error;
675
706
  if (isUnsupportedParserInputError(error) || isNonNativeParserUnavailableError(error)) {
676
707
  return [file, createEmptyModuleIndex(file), [], undefined];
677
708
  }
@@ -728,6 +759,17 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
728
759
  ensureJsonModule(modules, jsonPath);
729
760
  }
730
761
  expandStarImports(modules, opts);
762
+ if (manifestEntries) {
763
+ for (const [file, signature] of fileSignatures) {
764
+ if (manifestEntries.has(file))
765
+ continue;
766
+ manifestEntries.set(file, {
767
+ sig: signature.sig,
768
+ ...(signature.gitSig ? { gitSig: signature.gitSig } : {}),
769
+ edges: [],
770
+ });
771
+ }
772
+ }
731
773
  if (manifestEntries) {
732
774
  await writeIndexManifestSnapshot({
733
775
  projectRoot,
@@ -741,6 +783,12 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
741
783
  ...(helperOpts?.symlinkDirectories !== undefined ? { symlinkDirectories: helperOpts.symlinkDirectories } : {}),
742
784
  });
743
785
  }
786
+ const indexManifestEntries = manifestEntries
787
+ ? projectIndexManifestEntries(Array.from(manifestEntries, ([file, entry]) => {
788
+ const cacheSig = fileSignatures.get(file)?.cacheSig;
789
+ return [file, { ...entry, ...(cacheSig ? { cacheSig } : {}) }];
790
+ }))
791
+ : manifestEntriesForIndex;
744
792
  const index = await finalizeProjectIndex({
745
793
  projectRoot,
746
794
  normalizedProjectRoot,
@@ -753,7 +801,7 @@ async function buildIndexFromFileListShared(projectRoot, rawFiles, opts, helperO
753
801
  bloomFilterCache,
754
802
  ...(projectFiles !== undefined ? { projectFiles } : {}),
755
803
  buildReport: report,
756
- manifestEntries: manifestEntriesForIndex,
804
+ manifestEntries: indexManifestEntries,
757
805
  });
758
806
  if (manifestEntries) {
759
807
  await writeProjectIndexSnapshot(projectRoot, opts, index, projectSnapshotFilesSignature(manifestEntries, projectRoot));
@@ -776,34 +824,29 @@ async function buildProjectIndexWithManifestOptions(projectRoot, opts, helperOpt
776
824
  // full-tree symlink probe. Off and memory modes never read or write this disk
777
825
  // manifest, keeping read-only builds from mutating the project root. A missing or
778
826
  // unusable manifest falls back to probing once.
779
- // A symlink hint never expires on its own: `knownSymlinkDirectories` disables probing entirely, so
780
- // a directory symlinked in after the hint was recorded (e.g. `npm link`) would
781
- // otherwise never be discovered. `--cache-strict`/`--cache-verify` are explicit asks
782
- // for maximum correctness over speed, so both force a fresh probe here too.
827
+ // The manifest records the project-root directory mtime alongside symlink hints. A changed
828
+ // root mtime triggers the cheap full-tree probe, while strict modes always probe.
783
829
  const wantsMaxSymlinkCorrectness = !!opts?.cacheStrict || !!opts?.cacheVerify;
784
830
  const symlinkHintManifest = helperOpts?.ignoreExistingManifest || wantsMaxSymlinkCorrectness || !useDiskCache
785
831
  ? null
786
832
  : await loadManifest(projectRoot, opts);
787
- const knownSymlinkDirectories = symlinkHintManifest?.symlinkDirectories;
833
+ const rootMtime = symlinkHintManifest ? (await fsp.stat(projectRoot)).mtimeMs : undefined;
834
+ const symlinkHintIsFresh = symlinkHintManifest?.symlinkDirectoriesRootMtimeMs !== undefined &&
835
+ rootMtime === symlinkHintManifest.symlinkDirectoriesRootMtimeMs;
836
+ const knownSymlinkDirectories = symlinkHintIsFresh ? symlinkHintManifest?.symlinkDirectories : undefined;
788
837
  let discoveredSymlinkDirectories = knownSymlinkDirectories;
789
838
  const onSymlinkDirectoriesDiscovered = (directories) => {
790
839
  discoveredSymlinkDirectories = Array.from(directories);
791
840
  };
792
841
  // When the hint is unknown, listProjectFiles() and discoverProjectFiles() must run
793
- // sequentially rather than in Promise.all: both would otherwise start their own
794
- // full-tree symlink probe concurrently, since the callback only reports back after
795
- // listProjectFiles() resolves, too late to inform a probe discoverProjectFiles()
796
- // already started on its own. Sequencing costs a little parallelism on that one
797
- // cold-start case, but avoids paying for two full-tree walks instead of one. Once a
798
- // hint is known (the common warm case), both calls skip probing entirely, so running
799
- // them sequentially here costs no meaningful time either way.
842
+ // sequentially rather than in Promise.all to avoid duplicate full-tree probes.
800
843
  const discoveredFiles = await listProjectFiles(projectRoot, projectPatternsForLanguageExtensions(opts), {
801
844
  ...opts?.discovery,
802
845
  ...(opts?.logLevel ? { logLevel: opts.logLevel } : {}),
803
846
  ...(knownSymlinkDirectories !== undefined ? { knownSymlinkDirectories } : {}),
804
847
  onSymlinkDirectoriesDiscovered,
805
848
  });
806
- const additionalFileCandidates = normalizeIndexedFileInputs(projectRoot, opts?.additionalFiles ?? [], "Additional index file");
849
+ const additionalFileCandidates = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.additionalFiles ?? [], "Additional index file");
807
850
  const additionalFileExistence = await probePathExistence(additionalFileCandidates, buildConcurrency(opts));
808
851
  const additionalFiles = additionalFileCandidates.filter((file) => additionalFileExistence.get(file));
809
852
  const discoveredFileSet = new Set(discoveredFiles);
@@ -850,9 +893,11 @@ export async function buildProjectIndex(projectRoot, opts) {
850
893
  export async function buildProjectIndexFromFiles(projectRoot, inputFiles, opts) {
851
894
  try {
852
895
  const useDiskCache = (opts?.cache ?? "off") === "disk";
853
- return await buildIndexFromFileListShared(projectRoot, inputFiles, opts, {
896
+ const normalizedInputFiles = await normalizeIndexedFileInputsWithinRoot(projectRoot, inputFiles, "Index file");
897
+ return await buildIndexFromFileListShared(projectRoot, normalizedInputFiles, opts, {
854
898
  manifestMode: useDiskCache ? "read-only" : "off",
855
899
  warnNoFilesMessage: `Warning: No files provided for indexing in ${projectRoot}. Check the explicit file list and include/ignore filters. Diagnostic: codegraph doctor`,
900
+ confineReads: true,
856
901
  });
857
902
  }
858
903
  finally {
@@ -893,7 +938,7 @@ async function buildDeclaredScopeIndex(projectRoot, scopeFiles, opts) {
893
938
  */
894
939
  export async function buildProjectIndexIncremental(projectRoot, opts) {
895
940
  await initializeFileIdentityCaseSensitivity(projectRoot);
896
- clearImportResolutionCaches();
941
+ clearResolutionCaches();
897
942
  const graphOptions = normalizeGraphOptions(opts?.graph);
898
943
  const strictIncremental = opts?.incrementalStrict ?? false;
899
944
  if (strictIncremental && graphOptions.fast)
@@ -944,7 +989,7 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
944
989
  }
945
990
  startCheckProgress();
946
991
  const manifestStart = performance.now();
947
- const manifest = await loadManifest(projectRoot, opts);
992
+ const manifest = await loadManifest(projectRoot, opts, report);
948
993
  if (timings)
949
994
  timings.manifestMs = Math.round(performance.now() - manifestStart);
950
995
  const manifestUsed = !!manifest;
@@ -1050,8 +1095,8 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1050
1095
  const trackedEntryKeys = Object.keys(trackedEntries);
1051
1096
  let manifestRequiresSanitization = manifestFileKeys.length !== trackedEntryKeys.length ||
1052
1097
  manifestFileKeys.some((file) => !Object.hasOwn(trackedEntries, file));
1053
- const explicitFiles = normalizeIndexedFileInputs(projectRoot, opts?.files ?? [], "Incremental file");
1054
- const additionalFiles = normalizeIndexedFileInputs(projectRoot, opts?.additionalFiles ?? [], "Additional index file");
1098
+ const explicitFiles = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.files ?? [], "Incremental file");
1099
+ const additionalFiles = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.additionalFiles ?? [], "Additional index file");
1055
1100
  const previousTransientFiles = sanitizeManifestTransientFilesForRoot(projectRoot, projectRoot, manifest.transientFiles).filter((file) => Object.hasOwn(trackedEntries, file));
1056
1101
  const previousTransientFileSet = new Set(previousTransientFiles);
1057
1102
  const needsGitScan = !!opts?.gitBase || !!opts?.changedSince;
@@ -1185,7 +1230,7 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1185
1230
  const explicitFileSet = new Set(explicitFiles);
1186
1231
  const explicitFilesCoverAllFiles = explicitFileSet.size === allFiles.size && [...allFiles].every((file) => explicitFileSet.has(file));
1187
1232
  const explicitFilesAreChangeInputs = !opts?.filesAreProjectScope;
1188
- if (explicitFileSet.size && explicitFilesAreChangeInputs && (!explicitFilesCoverAllFiles || report)) {
1233
+ if (explicitFileSet.size && explicitFilesAreChangeInputs && (!explicitFilesCoverAllFiles || opts?.report)) {
1189
1234
  explicitFileSet.forEach(markAsChanged);
1190
1235
  }
1191
1236
  dependentFilesOfDeletedTracked.forEach(markAsChanged);
@@ -1195,7 +1240,7 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1195
1240
  if (changedFiles.size || deletedTrackedFiles.size || manifestRequiresSanitization)
1196
1241
  return null;
1197
1242
  const manifestEntryMap = new Map(Object.entries(trackedEntries));
1198
- const snapshotLoad = await tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntryMap);
1243
+ const snapshotLoad = await tryLoadProjectIndexSnapshot(projectRoot, opts, manifestEntryMap, report);
1199
1244
  if (!snapshotLoad)
1200
1245
  return null;
1201
1246
  const snapshot = snapshotLoad.index;
@@ -1275,6 +1320,7 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1275
1320
  })
1276
1321
  : new Map();
1277
1322
  const fileSignatures = await prepareFileSignatures({
1323
+ projectRoot,
1278
1324
  files: Array.from(allFiles),
1279
1325
  opts,
1280
1326
  gitSigMap,
@@ -1300,8 +1346,9 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1300
1346
  changedFiles.add(file);
1301
1347
  }
1302
1348
  }
1349
+ const reverseDeps = buildTrackedFileReverseDependencies(trackedEntries);
1303
1350
  const invalidateCachedDependents = () => {
1304
- const dependentFilesOfChanged = collectTrackedFileDependents(trackedEntries, changedFiles);
1351
+ const dependentFilesOfChanged = collectTrackedFileDependents(trackedEntries, changedFiles, reverseDeps);
1305
1352
  for (const file of dependentFilesOfChanged) {
1306
1353
  const key = fileIdentityKey(file);
1307
1354
  if (modules.has(key)) {
@@ -1326,9 +1373,11 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1326
1373
  return unchangedSnapshot;
1327
1374
  }
1328
1375
  const snapshotModules = cacheEnabled
1329
- ? await tryLoadProjectSnapshotModules(projectRoot, opts, fileSignatures)
1376
+ ? await tryLoadProjectSnapshotModules(projectRoot, opts, fileSignatures, report)
1377
+ : null;
1378
+ const persistedBloomFilters = bloomFilterCache
1379
+ ? await tryLoadPersistedBloomFilters(projectRoot, opts, report)
1330
1380
  : null;
1331
- const persistedBloomFilters = bloomFilterCache ? await tryLoadPersistedBloomFilters(projectRoot, opts) : null;
1332
1381
  for (const file of allFiles) {
1333
1382
  if (changedFiles.has(file))
1334
1383
  continue;
@@ -1481,6 +1530,7 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1481
1530
  dynamicImportHeuristics: !!graphOptions.dynamicImportHeuristics,
1482
1531
  ...(opts?.native ? { native: opts.native } : {}),
1483
1532
  ...(opts?.languageExtensions ? { languageExtensions: opts.languageExtensions } : {}),
1533
+ threads: conc,
1484
1534
  ...(opts?.logLevel ? { logLevel: opts.logLevel } : {}),
1485
1535
  ...(graphOptions.resolutionHints ? { resolutionHints: graphOptions.resolutionHints } : {}),
1486
1536
  allFiles: Array.from(allFiles),
@@ -1498,6 +1548,16 @@ export async function buildProjectIndexIncremental(projectRoot, opts) {
1498
1548
  });
1499
1549
  if (timings)
1500
1550
  timings.graphMs = Math.round(performance.now() - graphStart);
1551
+ for (const file of new Set([...changedFiles, ...transientFiles])) {
1552
+ const signature = fileSignatures.get(file);
1553
+ if (!signature || manifestEntries.has(file))
1554
+ continue;
1555
+ manifestEntries.set(file, {
1556
+ sig: signature.sig,
1557
+ ...(signature.gitSig ? { gitSig: signature.gitSig } : {}),
1558
+ edges: [],
1559
+ });
1560
+ }
1501
1561
  await writeIndexManifestSnapshot({
1502
1562
  projectRoot,
1503
1563
  opts,
@@ -1565,8 +1625,8 @@ export async function buildGraphDelta(projectRoot, opts) {
1565
1625
  const strictIncremental = opts?.incrementalStrict ?? false;
1566
1626
  if (strictIncremental && graphOptions.fast)
1567
1627
  graphOptions.fast = false;
1568
- const explicitFiles = normalizeIndexedFileInputs(projectRoot, opts?.files ?? [], "Graph delta file");
1569
- const additionalFiles = normalizeIndexedFileInputs(projectRoot, opts?.additionalFiles ?? [], "Additional graph delta file");
1628
+ const explicitFiles = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.files ?? [], "Graph delta file");
1629
+ const additionalFiles = await normalizeIndexedFileInputsWithinRoot(projectRoot, opts?.additionalFiles ?? [], "Additional graph delta file");
1570
1630
  const needsGitScan = !!opts?.gitBase || !!opts?.changedSince;
1571
1631
  const gitFiles = needsGitScan ? await listChangedFiles(projectRoot, buildIncrementalGitDiffOptions(opts)) : [];
1572
1632
  const { trackedFiles } = await partitionTrackedManifestFiles(trackedEntries);
@@ -1591,14 +1651,19 @@ export async function buildGraphDelta(projectRoot, opts) {
1591
1651
  }
1592
1652
  const candidateExistence = await probePathExistence([...explicitFiles, ...additionalFiles, ...manifestDiffFiles, ...gitFiles], buildConcurrency(opts));
1593
1653
  const existsInCandidateSnapshot = (file) => candidateExistence.get(file) ?? false;
1594
- const existingExplicitFiles = explicitFiles.filter(existsInCandidateSnapshot);
1654
+ const normalizeChangedFiles = (files) => files.map((file) => {
1655
+ if (!existsInCandidateSnapshot(file))
1656
+ return file;
1657
+ const [normalizedFile] = normalizeIndexedFileInputs(projectRoot, [file], "Graph delta file");
1658
+ return normalizedFile ?? file;
1659
+ }), normalizedManifestDiffFiles = normalizeChangedFiles(manifestDiffFiles), normalizedGitFiles = normalizeChangedFiles(gitFiles), existingExplicitFiles = explicitFiles.filter(existsInCandidateSnapshot);
1595
1660
  const existingAdditionalFiles = additionalFiles.filter(existsInCandidateSnapshot);
1596
1661
  const allFiles = new Set([
1597
1662
  ...trackedFiles,
1598
1663
  ...existingExplicitFiles,
1599
1664
  ...existingAdditionalFiles,
1600
- ...manifestDiffFiles.filter(existsInCandidateSnapshot),
1601
- ...gitFiles.filter(existsInCandidateSnapshot),
1665
+ ...normalizedManifestDiffFiles.filter((_, index) => existsInCandidateSnapshot(manifestDiffFiles[index])),
1666
+ ...normalizedGitFiles.filter((_, index) => existsInCandidateSnapshot(gitFiles[index])),
1602
1667
  ]);
1603
1668
  const changedFiles = new Set();
1604
1669
  const changedFileKeys = new Set();
@@ -1610,8 +1675,8 @@ export async function buildGraphDelta(projectRoot, opts) {
1610
1675
  changedFiles.add(file);
1611
1676
  };
1612
1677
  existingExplicitFiles.forEach(addChangedFile);
1613
- manifestDiffFiles.forEach(addChangedFile);
1614
- gitFiles.forEach(addChangedFile);
1678
+ normalizedManifestDiffFiles.forEach(addChangedFile);
1679
+ normalizedGitFiles.forEach(addChangedFile);
1615
1680
  if (languageExtensionsChanged) {
1616
1681
  for (const file of trackedFiles) {
1617
1682
  if (languageSupportChangedForFile(file))