gitnexus 1.6.11-rc.8 → 1.6.11

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 (531) hide show
  1. package/README.md +95 -26
  2. package/dist/_shared/graph/types.d.ts +81 -2
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/integrations/circuit-breaker.d.ts.map +1 -1
  5. package/dist/_shared/integrations/circuit-breaker.js.map +1 -1
  6. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  7. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  8. package/dist/_shared/language-detection.d.ts.map +1 -1
  9. package/dist/_shared/language-detection.js +2 -0
  10. package/dist/_shared/language-detection.js.map +1 -1
  11. package/dist/_shared/languages.d.ts +2 -1
  12. package/dist/_shared/languages.d.ts.map +1 -1
  13. package/dist/_shared/languages.js +1 -0
  14. package/dist/_shared/languages.js.map +1 -1
  15. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  16. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  17. package/dist/_shared/lbug/schema-constants.js +4 -0
  18. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  19. package/dist/_shared/scope-resolution/evidence-weights.d.ts.map +1 -1
  20. package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -0
  21. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  22. package/dist/_shared/scope-resolution/language-classification.d.ts +3 -0
  23. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/language-classification.js +4 -0
  25. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  26. package/dist/_shared/scope-resolution/reference-site.d.ts +10 -0
  27. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  28. package/dist/_shared/scope-resolution/registries/field-registry.js.map +1 -1
  29. package/dist/_shared/scope-resolution/registries/method-registry.js.map +1 -1
  30. package/dist/_shared/scope-resolution/scope-tree.d.ts.map +1 -1
  31. package/dist/_shared/scope-resolution/scope-tree.js.map +1 -1
  32. package/dist/_shared/scope-resolution/types.d.ts +15 -0
  33. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  34. package/dist/cli/ai-context.d.ts +4 -0
  35. package/dist/cli/ai-context.js +90 -14
  36. package/dist/cli/analyze-config.js +14 -0
  37. package/dist/cli/analyze-options.d.ts +14 -0
  38. package/dist/cli/analyze-watch.d.ts +20 -0
  39. package/dist/cli/analyze-watch.js +434 -0
  40. package/dist/cli/analyze.js +27 -9
  41. package/dist/cli/auto-sync.d.ts +1 -0
  42. package/dist/cli/auto-sync.js +107 -0
  43. package/dist/cli/command-banner.d.ts +15 -0
  44. package/dist/cli/command-banner.js +42 -0
  45. package/dist/cli/detect-changes-format.js +21 -0
  46. package/dist/cli/doctor.d.ts +7 -0
  47. package/dist/cli/doctor.js +14 -0
  48. package/dist/cli/group.js +7 -1
  49. package/dist/cli/help-i18n.js +4 -0
  50. package/dist/cli/i18n/en.d.ts +18 -3
  51. package/dist/cli/i18n/en.js +18 -3
  52. package/dist/cli/i18n/resources.d.ts +33 -3
  53. package/dist/cli/i18n/zh-CN.d.ts +15 -0
  54. package/dist/cli/i18n/zh-CN.js +18 -3
  55. package/dist/cli/index.js +34 -7
  56. package/dist/cli/mcp.d.ts +15 -0
  57. package/dist/cli/mcp.js +44 -0
  58. package/dist/cli/optional-grammars.d.ts +3 -2
  59. package/dist/cli/optional-grammars.js +19 -3
  60. package/dist/cli/setup.js +41 -15
  61. package/dist/cli/update-notice.d.ts +34 -0
  62. package/dist/cli/update-notice.js +91 -0
  63. package/dist/cli/update.d.ts +21 -0
  64. package/dist/cli/update.js +93 -0
  65. package/dist/cli/watch.d.ts +1 -20
  66. package/dist/cli/watch.js +5 -371
  67. package/dist/core/analysis-feature-registry.d.ts +2 -0
  68. package/dist/core/analysis-feature-registry.js +15 -0
  69. package/dist/core/analyzer-identity.js +21 -3
  70. package/dist/core/auto-sync/analysis-worker-launch.d.ts +30 -0
  71. package/dist/core/auto-sync/analysis-worker-launch.js +166 -0
  72. package/dist/core/auto-sync/config.d.ts +33 -0
  73. package/dist/core/auto-sync/config.js +320 -0
  74. package/dist/core/auto-sync/index.d.ts +6 -0
  75. package/dist/core/auto-sync/index.js +6 -0
  76. package/dist/core/auto-sync/path-security.d.ts +9 -0
  77. package/dist/core/auto-sync/path-security.js +251 -0
  78. package/dist/core/auto-sync/repo.d.ts +1 -0
  79. package/dist/core/auto-sync/repo.js +6 -0
  80. package/dist/core/auto-sync/runner.d.ts +44 -0
  81. package/dist/core/auto-sync/runner.js +428 -0
  82. package/dist/core/auto-sync/starter.d.ts +50 -0
  83. package/dist/core/auto-sync/starter.js +497 -0
  84. package/dist/core/auto-sync/state.d.ts +37 -0
  85. package/dist/core/auto-sync/state.js +119 -0
  86. package/dist/core/group/config-parser.js +8 -1
  87. package/dist/core/group/cross-impact.d.ts +3 -0
  88. package/dist/core/group/cross-impact.js +36 -4
  89. package/dist/core/group/extractors/http-patterns/java.js +22 -8
  90. package/dist/core/group/extractors/http-patterns/kotlin.js +86 -31
  91. package/dist/core/group/extractors/http-patterns/node.js +145 -8
  92. package/dist/core/group/extractors/http-patterns/python.js +11 -7
  93. package/dist/core/group/extractors/http-route-extractor.js +63 -17
  94. package/dist/core/group/extractors/java-workspace-extractor.js +244 -31
  95. package/dist/core/group/group-lock.js +5 -6
  96. package/dist/core/group/normalization.d.ts +38 -1
  97. package/dist/core/group/normalization.js +59 -3
  98. package/dist/core/group/service.d.ts +11 -0
  99. package/dist/core/group/service.js +13 -1
  100. package/dist/core/group/storage.js +2 -2
  101. package/dist/core/group/sync.d.ts +24 -1
  102. package/dist/core/group/sync.js +46 -8
  103. package/dist/core/group/types.d.ts +13 -0
  104. package/dist/core/incremental/derived-writeback.d.ts +36 -0
  105. package/dist/core/incremental/derived-writeback.js +68 -0
  106. package/dist/core/incremental/spring-config-drift.d.ts +12 -0
  107. package/dist/core/incremental/spring-config-drift.js +46 -0
  108. package/dist/core/incremental/subgraph-extract.d.ts +7 -4
  109. package/dist/core/incremental/subgraph-extract.js +30 -5
  110. package/dist/core/ingestion/asyncapi/document.d.ts +226 -0
  111. package/dist/core/ingestion/asyncapi/document.js +758 -0
  112. package/dist/core/ingestion/asyncapi/protocol.d.ts +79 -0
  113. package/dist/core/ingestion/asyncapi/protocol.js +203 -0
  114. package/dist/core/ingestion/call-extractors/configs/zig.d.ts +2 -0
  115. package/dist/core/ingestion/call-extractors/configs/zig.js +4 -0
  116. package/dist/core/ingestion/call-extractors/zig-static-gating.d.ts +100 -0
  117. package/dist/core/ingestion/call-extractors/zig-static-gating.js +319 -0
  118. package/dist/core/ingestion/call-processor.js +3 -1
  119. package/dist/core/ingestion/class-extractors/configs/zig.d.ts +2 -0
  120. package/dist/core/ingestion/class-extractors/configs/zig.js +32 -0
  121. package/dist/core/ingestion/class-extractors/generic.js +4 -1
  122. package/dist/core/ingestion/class-types.d.ts +6 -2
  123. package/dist/core/ingestion/destination-key.d.ts +59 -0
  124. package/dist/core/ingestion/destination-key.js +61 -0
  125. package/dist/core/ingestion/entry-point-scoring.d.ts +6 -2
  126. package/dist/core/ingestion/entry-point-scoring.js +8 -44
  127. package/dist/core/ingestion/export-detection.d.ts +37 -0
  128. package/dist/core/ingestion/export-detection.js +60 -0
  129. package/dist/core/ingestion/field-extractors/configs/zig.d.ts +8 -0
  130. package/dist/core/ingestion/field-extractors/configs/zig.js +49 -0
  131. package/dist/core/ingestion/field-extractors/generic.d.ts +1 -1
  132. package/dist/core/ingestion/field-extractors/generic.js +12 -1
  133. package/dist/core/ingestion/frameworks/spring/actuator-runtime.d.ts +26 -0
  134. package/dist/core/ingestion/frameworks/spring/actuator-runtime.js +843 -0
  135. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +5 -0
  136. package/dist/core/ingestion/frameworks/spring/analysis-features.js +9 -0
  137. package/dist/core/ingestion/frameworks/spring/annotation-arguments.js +8 -1
  138. package/dist/core/ingestion/frameworks/spring/argument-facts.d.ts +80 -0
  139. package/dist/core/ingestion/frameworks/spring/argument-facts.js +85 -0
  140. package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +1 -0
  141. package/dist/core/ingestion/frameworks/spring/config-bindings.js +2 -1
  142. package/dist/core/ingestion/frameworks/spring/destinations.d.ts +539 -0
  143. package/dist/core/ingestion/frameworks/spring/destinations.js +840 -0
  144. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.d.ts +22 -0
  145. package/dist/core/ingestion/frameworks/spring/dynamic-lookups.js +124 -0
  146. package/dist/core/ingestion/frameworks/spring/message-producers.d.ts +78 -0
  147. package/dist/core/ingestion/frameworks/spring/message-producers.js +90 -0
  148. package/dist/core/ingestion/frameworks/spring/non-http-handlers.d.ts +29 -0
  149. package/dist/core/ingestion/frameworks/spring/vendor-prefixes.d.ts +7 -0
  150. package/dist/core/ingestion/frameworks/spring/vendor-prefixes.js +22 -0
  151. package/dist/core/ingestion/import-resolvers/configs/zig.d.ts +13 -0
  152. package/dist/core/ingestion/import-resolvers/configs/zig.js +26 -0
  153. package/dist/core/ingestion/import-resolvers/zig.d.ts +34 -0
  154. package/dist/core/ingestion/import-resolvers/zig.js +193 -0
  155. package/dist/core/ingestion/language-config.d.ts +177 -0
  156. package/dist/core/ingestion/language-config.js +719 -0
  157. package/dist/core/ingestion/language-provider.d.ts +178 -1
  158. package/dist/core/ingestion/language-provider.js +22 -0
  159. package/dist/core/ingestion/languages/csharp/razor-view-components.d.ts +62 -0
  160. package/dist/core/ingestion/languages/csharp/razor-view-components.js +954 -0
  161. package/dist/core/ingestion/languages/csharp/resolution-config.d.ts +3 -0
  162. package/dist/core/ingestion/languages/csharp/resolution-config.js +6 -1
  163. package/dist/core/ingestion/languages/csharp/scope-resolver.js +8 -0
  164. package/dist/core/ingestion/languages/index.d.ts +1 -0
  165. package/dist/core/ingestion/languages/index.js +2 -0
  166. package/dist/core/ingestion/languages/java/analysis-features.d.ts +1 -1
  167. package/dist/core/ingestion/languages/java/analysis-features.js +14 -6
  168. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +8 -0
  169. package/dist/core/ingestion/languages/java/capture-side-channel.js +34 -0
  170. package/dist/core/ingestion/languages/java/captures.js +22 -1
  171. package/dist/core/ingestion/languages/java/lombok-synthesizer.d.ts +42 -0
  172. package/dist/core/ingestion/languages/java/lombok-synthesizer.js +439 -0
  173. package/dist/core/ingestion/languages/java/scope-resolver.js +2 -0
  174. package/dist/core/ingestion/languages/java/spring-actuator.d.ts +2 -0
  175. package/dist/core/ingestion/languages/java/spring-actuator.js +62 -0
  176. package/dist/core/ingestion/languages/java/spring-di.d.ts +17 -1
  177. package/dist/core/ingestion/languages/java/spring-di.js +44 -2
  178. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.d.ts +8 -0
  179. package/dist/core/ingestion/languages/java/spring-dynamic-lookup.js +62 -0
  180. package/dist/core/ingestion/languages/java/spring-message-producers.d.ts +20 -0
  181. package/dist/core/ingestion/languages/java/spring-message-producers.js +83 -0
  182. package/dist/core/ingestion/languages/java/spring-non-http-handlers.d.ts +11 -1
  183. package/dist/core/ingestion/languages/java/spring-non-http-handlers.js +13 -3
  184. package/dist/core/ingestion/languages/java.js +18 -8
  185. package/dist/core/ingestion/languages/jvm/accessor-synthesis.d.ts +99 -0
  186. package/dist/core/ingestion/languages/jvm/accessor-synthesis.js +173 -0
  187. package/dist/core/ingestion/languages/jvm/beanspec.d.ts +17 -0
  188. package/dist/core/ingestion/languages/jvm/beanspec.js +42 -0
  189. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +15 -0
  190. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +50 -0
  191. package/dist/core/ingestion/languages/kotlin/captures.js +24 -1
  192. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.d.ts +26 -0
  193. package/dist/core/ingestion/languages/kotlin/lombok-synthesizer.js +417 -0
  194. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +4 -0
  195. package/dist/core/ingestion/languages/kotlin/spring-actuator.d.ts +4 -0
  196. package/dist/core/ingestion/languages/kotlin/spring-actuator.js +172 -0
  197. package/dist/core/ingestion/languages/kotlin/spring-config-bindings.d.ts +18 -0
  198. package/dist/core/ingestion/languages/kotlin/spring-config-bindings.js +411 -0
  199. package/dist/core/ingestion/languages/kotlin/spring-di.d.ts +51 -1
  200. package/dist/core/ingestion/languages/kotlin/spring-di.js +86 -6
  201. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.d.ts +8 -0
  202. package/dist/core/ingestion/languages/kotlin/spring-dynamic-lookup.js +77 -0
  203. package/dist/core/ingestion/languages/kotlin/spring-message-producers.d.ts +17 -0
  204. package/dist/core/ingestion/languages/kotlin/spring-message-producers.js +119 -0
  205. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.d.ts +16 -0
  206. package/dist/core/ingestion/languages/kotlin/spring-non-http-handlers.js +77 -2
  207. package/dist/core/ingestion/languages/kotlin.js +24 -0
  208. package/dist/core/ingestion/languages/python.js +2 -0
  209. package/dist/core/ingestion/languages/rust/query.js +8 -8
  210. package/dist/core/ingestion/languages/zig/captures.d.ts +260 -0
  211. package/dist/core/ingestion/languages/zig/captures.js +2070 -0
  212. package/dist/core/ingestion/languages/zig/index.d.ts +4 -0
  213. package/dist/core/ingestion/languages/zig/index.js +4 -0
  214. package/dist/core/ingestion/languages/zig/interpret.d.ts +36 -0
  215. package/dist/core/ingestion/languages/zig/interpret.js +176 -0
  216. package/dist/core/ingestion/languages/zig/query.d.ts +3 -0
  217. package/dist/core/ingestion/languages/zig/query.js +426 -0
  218. package/dist/core/ingestion/languages/zig/range-binding.d.ts +37 -0
  219. package/dist/core/ingestion/languages/zig/range-binding.js +373 -0
  220. package/dist/core/ingestion/languages/zig/scope-resolver.d.ts +12 -0
  221. package/dist/core/ingestion/languages/zig/scope-resolver.js +58 -0
  222. package/dist/core/ingestion/languages/zig/simple-hooks.d.ts +25 -0
  223. package/dist/core/ingestion/languages/zig/simple-hooks.js +143 -0
  224. package/dist/core/ingestion/languages/zig.d.ts +32 -0
  225. package/dist/core/ingestion/languages/zig.js +130 -0
  226. package/dist/core/ingestion/method-extractors/configs/zig.d.ts +2 -0
  227. package/dist/core/ingestion/method-extractors/configs/zig.js +120 -0
  228. package/dist/core/ingestion/method-extractors/generic.js +16 -4
  229. package/dist/core/ingestion/method-types.d.ts +10 -4
  230. package/dist/core/ingestion/model/field-registry.d.ts +3 -3
  231. package/dist/core/ingestion/model/field-registry.js +11 -7
  232. package/dist/core/ingestion/model/method-registry.d.ts +3 -3
  233. package/dist/core/ingestion/model/method-registry.js +13 -8
  234. package/dist/core/ingestion/model/registration-table.js +3 -0
  235. package/dist/core/ingestion/model/type-registry.js +8 -4
  236. package/dist/core/ingestion/pipeline-phases/di.js +47 -14
  237. package/dist/core/ingestion/pipeline-phases/index.d.ts +1 -0
  238. package/dist/core/ingestion/pipeline-phases/index.js +1 -0
  239. package/dist/core/ingestion/pipeline-phases/parse-impl.d.ts +7 -1
  240. package/dist/core/ingestion/pipeline-phases/parse-impl.js +79 -91
  241. package/dist/core/ingestion/pipeline-phases/parse.d.ts +17 -0
  242. package/dist/core/ingestion/pipeline-phases/processes.d.ts +2 -1
  243. package/dist/core/ingestion/pipeline-phases/processes.js +39 -4
  244. package/dist/core/ingestion/pipeline-phases/routes.js +27 -18
  245. package/dist/core/ingestion/pipeline-phases/runner.d.ts +4 -1
  246. package/dist/core/ingestion/pipeline-phases/runner.js +34 -14
  247. package/dist/core/ingestion/pipeline-phases/scan.js +82 -1
  248. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.d.ts +2 -0
  249. package/dist/core/ingestion/pipeline-phases/spring-auto-configuration.js +8 -0
  250. package/dist/core/ingestion/pipeline-phases/spring-destinations.d.ts +123 -0
  251. package/dist/core/ingestion/pipeline-phases/spring-destinations.js +688 -0
  252. package/dist/core/ingestion/pipeline.d.ts +30 -1
  253. package/dist/core/ingestion/pipeline.js +52 -14
  254. package/dist/core/ingestion/resolve-references.js +5 -0
  255. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +16 -0
  256. package/dist/core/ingestion/route-extractors/constant-resolver.js +10 -0
  257. package/dist/core/ingestion/route-extractors/java-const-resolver.d.ts +27 -1
  258. package/dist/core/ingestion/route-extractors/java-const-resolver.js +161 -13
  259. package/dist/core/ingestion/route-extractors/kotlin-const-resolver.d.ts +12 -18
  260. package/dist/core/ingestion/route-extractors/kotlin-const-resolver.js +214 -33
  261. package/dist/core/ingestion/route-extractors/kotlin-spring.d.ts +13 -0
  262. package/dist/core/ingestion/route-extractors/kotlin-spring.js +259 -0
  263. package/dist/core/ingestion/route-extractors/python-decorator-handler.d.ts +6 -0
  264. package/dist/core/ingestion/route-extractors/python-decorator-handler.js +16 -0
  265. package/dist/core/ingestion/route-extractors/spring-shared.d.ts +30 -1
  266. package/dist/core/ingestion/route-extractors/spring-shared.js +77 -9
  267. package/dist/core/ingestion/route-extractors/spring.js +9 -5
  268. package/dist/core/ingestion/scope-extractor.js +8 -0
  269. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +62 -0
  270. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +4 -0
  271. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +2 -0
  272. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +28 -0
  273. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +11 -2
  274. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.d.ts +23 -2
  275. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +24 -3
  276. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +11 -1
  277. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +26 -6
  278. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.d.ts +11 -0
  279. package/dist/core/ingestion/scope-resolution/passes/compound-receiver.js +29 -3
  280. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +8 -1
  281. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +35 -9
  282. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +1 -4
  283. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.js +277 -9
  284. package/dist/core/ingestion/scope-resolution/pipeline/registry.js +2 -0
  285. package/dist/core/ingestion/scope-resolution/pipeline/run.js +7 -3
  286. package/dist/core/ingestion/scope-resolution/scope/walkers.d.ts +43 -9
  287. package/dist/core/ingestion/scope-resolution/scope/walkers.js +71 -10
  288. package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -0
  289. package/dist/core/ingestion/tree-sitter-queries.js +161 -0
  290. package/dist/core/ingestion/type-extractors/zig.d.ts +2 -0
  291. package/dist/core/ingestion/type-extractors/zig.js +17 -0
  292. package/dist/core/ingestion/utils/ast-helpers.d.ts +40 -1
  293. package/dist/core/ingestion/utils/ast-helpers.js +124 -6
  294. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +9 -0
  295. package/dist/core/ingestion/utils/callable-flow-captures.js +75 -14
  296. package/dist/core/ingestion/utils/test-file-path.d.ts +28 -0
  297. package/dist/core/ingestion/utils/test-file-path.js +87 -0
  298. package/dist/core/ingestion/variable-extractors/configs/zig.d.ts +2 -0
  299. package/dist/core/ingestion/variable-extractors/configs/zig.js +71 -0
  300. package/dist/core/ingestion/workers/parse-worker.js +85 -14
  301. package/dist/core/install-context.d.ts +4 -0
  302. package/dist/core/install-context.js +152 -0
  303. package/dist/core/lbug/csv-generator.d.ts +10 -1
  304. package/dist/core/lbug/csv-generator.js +92 -22
  305. package/dist/core/lbug/graph-emit-sink.d.ts +3 -2
  306. package/dist/core/lbug/graph-emit-sink.js +4 -2
  307. package/dist/core/lbug/lbug-adapter.d.ts +100 -5
  308. package/dist/core/lbug/lbug-adapter.js +236 -24
  309. package/dist/core/lbug/schema.d.ts +6 -5
  310. package/dist/core/lbug/schema.js +84 -22
  311. package/dist/core/net/url-guard.d.ts +6 -0
  312. package/dist/core/net/url-guard.js +147 -0
  313. package/dist/core/package-version.d.ts +5 -0
  314. package/dist/core/package-version.js +10 -0
  315. package/dist/core/run-analyze.d.ts +21 -4
  316. package/dist/core/run-analyze.js +426 -117
  317. package/dist/core/search/fts-indexes.d.ts +19 -1
  318. package/dist/core/search/fts-indexes.js +28 -1
  319. package/dist/core/tree-sitter/parser-loader.js +16 -0
  320. package/dist/core/update-cache.d.ts +39 -0
  321. package/dist/core/update-cache.js +141 -0
  322. package/dist/core/update-check.d.ts +31 -0
  323. package/dist/core/update-check.js +274 -0
  324. package/dist/mcp/local/local-backend.d.ts +27 -13
  325. package/dist/mcp/local/local-backend.js +148 -60
  326. package/dist/mcp/repository-policy.d.ts +5 -1
  327. package/dist/mcp/repository-policy.js +48 -4
  328. package/dist/mcp/resources.js +10 -1
  329. package/dist/mcp/server.js +8 -9
  330. package/dist/mcp/tools.js +32 -22
  331. package/dist/server/analyze-launch.d.ts +2 -0
  332. package/dist/server/analyze-launch.js +2 -0
  333. package/dist/server/analyze-worker-protocol.d.ts +6 -1
  334. package/dist/server/analyze-worker.d.ts +1 -0
  335. package/dist/server/analyze-worker.js +38 -20
  336. package/dist/server/api.d.ts +5 -1
  337. package/dist/server/api.js +105 -88
  338. package/dist/server/git-clone.d.ts +40 -16
  339. package/dist/server/git-clone.js +253 -199
  340. package/dist/server/grep-params.d.ts +18 -0
  341. package/dist/server/grep-params.js +83 -0
  342. package/dist/server/grep-scan.d.ts +23 -0
  343. package/dist/server/grep-scan.js +107 -0
  344. package/dist/server/grep-worker.d.ts +1 -0
  345. package/dist/server/grep-worker.js +12 -0
  346. package/dist/server/mcp-http.d.ts +8 -0
  347. package/dist/server/mcp-http.js +16 -1
  348. package/dist/server/update-controller.d.ts +29 -0
  349. package/dist/server/update-controller.js +82 -0
  350. package/dist/storage/file-lock.d.ts +15 -0
  351. package/dist/storage/file-lock.js +155 -0
  352. package/dist/storage/fs-atomic.d.ts +24 -0
  353. package/dist/storage/fs-atomic.js +86 -2
  354. package/dist/storage/global-dir.d.ts +2 -0
  355. package/dist/storage/global-dir.js +6 -0
  356. package/dist/storage/parse-cache.d.ts +45 -7
  357. package/dist/storage/parse-cache.js +189 -42
  358. package/dist/storage/parsedfile-store.d.ts +41 -60
  359. package/dist/storage/parsedfile-store.js +247 -171
  360. package/dist/storage/repo-manager.d.ts +10 -4
  361. package/dist/storage/repo-manager.js +35 -25
  362. package/dist/storage/repo-meta.d.ts +34 -0
  363. package/dist/storage/v8-sidecar.d.ts +48 -0
  364. package/dist/storage/v8-sidecar.js +347 -0
  365. package/dist/types/pipeline.d.ts +14 -0
  366. package/dist/utils/process-identity.d.ts +2 -0
  367. package/dist/utils/process-identity.js +35 -0
  368. package/package.json +10 -4
  369. package/scripts/assert-web-assets.mjs +35 -0
  370. package/scripts/build-web.js +72 -0
  371. package/scripts/build.js +31 -28
  372. package/scripts/cross-platform-tests.ts +5 -0
  373. package/skills/gitnexus-cli.md +5 -1
  374. package/web/assets/ProcessFlowModal-DAeX2BHW.js +24 -0
  375. package/web/assets/{abnfDiagram-QNN2D4NM-Cq2djWWe.js → abnfDiagram-PAR5IXJI-J3OdeHLl.js} +1 -1
  376. package/web/assets/{agent-BWAXPjC5.js → agent-BMRqXorA.js} +6 -4
  377. package/web/assets/architecture-7GRP2DOG-M7G3SWCO-G3sWyX6M.js +1 -0
  378. package/web/assets/architectureDiagram-2PNWDENW-ysKcRlGT.js +36 -0
  379. package/web/assets/blockDiagram-PUWGUBOA-oLXTa1lY.js +129 -0
  380. package/web/assets/c4Diagram-3NLNHZP5-D3iu4eC0.js +38 -0
  381. package/web/assets/{chunk-2SREHG4O-Dip42xOq.js → chunk-2NMSUPJH-B24w-wng.js} +1 -1
  382. package/web/assets/{chunk-VJFVEZTB-CX66F2ep.js → chunk-32MCUW2P-ByUyt0Sa.js} +3 -3
  383. package/web/assets/{chunk-4RFN2BYJ-DHHWuC-n.js → chunk-3NPNU5GP-DocZ07Sg.js} +1 -1
  384. package/web/assets/{chunk-XNMVGMAZ-Cg_LnPtj.js → chunk-3SMGFRGC-CAu4JRLv.js} +1 -1
  385. package/web/assets/{chunk-W44A43WB-BN8EQc_u.js → chunk-4CAJECRU-DRYMwG9z.js} +1 -1
  386. package/web/assets/chunk-4OADUZ5Q-CxrSvOwZ.js +10 -0
  387. package/web/assets/{chunk-DMV4VAQV-Bn6WXDSX.js → chunk-5IQCK5RY-CCMhl4so.js} +2 -2
  388. package/web/assets/{chunk-RRFMTAIC-CMN0wcYA.js → chunk-5MVFYWFU-Db9KvrYO.js} +1 -1
  389. package/web/assets/chunk-CLS4B6BI-Uvx5QNsu.js +168 -0
  390. package/web/assets/chunk-DZP67EKU-B3Mt380j.js +70 -0
  391. package/web/assets/{chunk-6L755F7B-CMhLBxi2.js → chunk-EICP7K5X-CqwE9hui.js} +1 -1
  392. package/web/assets/{chunk-BI6VK774-D0oaWk8V.js → chunk-GDY2UAB4-CtQQR0a8.js} +1 -1
  393. package/web/assets/chunk-H7VHZCWX-CE1nAmt6.js +1 -0
  394. package/web/assets/chunk-IJBDOHL6-BUKtY6oF.js +1 -0
  395. package/web/assets/{chunk-OIYT25JQ-CQ6KOZGX.js → chunk-JFFVMJIA-0fJenqia.js} +1 -1
  396. package/web/assets/{chunk-HNC4WDU7-DoU3KnA7.js → chunk-JZGDI5JK-BeTMSSkJ.js} +1 -1
  397. package/web/assets/{chunk-EQFTRU2I-1ix7TzW9.js → chunk-KD6SPIPN-Qp1Pflah.js} +1 -1
  398. package/web/assets/chunk-NF366YI6-CpSpya3n.js +231 -0
  399. package/web/assets/chunk-NUDPKBEF-CU1-BQIW.js +34 -0
  400. package/web/assets/{chunk-SATU7PGQ-B1zhgOvc.js → chunk-OJINMHTS-zOCQe4eI.js} +1 -1
  401. package/web/assets/{chunk-E5QJAATJ-dh-5CtIV.js → chunk-Q6NGPIAH-yyBomb63.js} +1 -1
  402. package/web/assets/chunk-QJSWEUOL-D_rf9gPD.js +128 -0
  403. package/web/assets/chunk-R7JDMUKV-CRoqKpD6.js +1 -0
  404. package/web/assets/{chunk-VE5CLXGZ-C1vB7wpY.js → chunk-RCXAM2GK-CUqrWQDV.js} +1 -1
  405. package/web/assets/{chunk-66DQ2XMT-CM0xjFAN.js → chunk-RT4MAWR3-zXy9-Lvt.js} +1 -1
  406. package/web/assets/{chunk-TZUXEDM2-B7p9AcTw.js → chunk-SFMINX4W-J2UrvMpD.js} +1 -1
  407. package/web/assets/{chunk-LORZLZWG-B57uGw2N.js → chunk-SLDQ463B-CHY6e_bQ.js} +2 -2
  408. package/web/assets/{chunk-FWYVLQTC-BgDItRzJ.js → chunk-TCEHX7R3-CXPDEVbm.js} +1 -1
  409. package/web/assets/{chunk-224SPVON-B8gxtXpy.js → chunk-VQC2EELJ-Dc8fIy4R.js} +1 -1
  410. package/web/assets/chunk-VRZKL3EH-DB3KixTQ.js +1 -0
  411. package/web/assets/{chunk-A7VWPJGB-B4O3oQdQ.js → chunk-VTHDQ7BV-b7FsPQZO.js} +1 -1
  412. package/web/assets/chunk-VY2OSTJR-Dkgc3Brg.js +2 -0
  413. package/web/assets/chunk-WUBWJARI-7FwILJ3k.js +2 -0
  414. package/web/assets/{chunk-D6VWDJW2-BxcBdZ9c.js → chunk-YBMQ5JGJ-BSnyWZmd.js} +1 -1
  415. package/web/assets/chunk-YDMLL4PJ-IHhMngTz.js +2 -0
  416. package/web/assets/chunk-Z6V44ARX-BjCEsF0Q.js +62 -0
  417. package/web/assets/chunk-ZJJ7VQJP-Dz089b-K.js +321 -0
  418. package/web/assets/chunk-ZNLK7HRR-B0iFpmW4.js +1 -0
  419. package/web/assets/chunk-ZQN7UHIL-Cy7KAjQt.js +1 -0
  420. package/web/assets/{chunk-L5GCOVLC-CE2w8Nm_.js → chunk-ZS6VBONO-DBjJO0w9.js} +2 -2
  421. package/web/assets/{chunk-NV3KIAZN-5yvcpMiu.js → chunk-ZUNWM646-DNRJyNPe.js} +1 -1
  422. package/web/assets/classDiagram-FGAMPOII-C5Ibyode.js +1 -0
  423. package/web/assets/classDiagram-v2-AI5RJEK4-C5Ibyode.js +1 -0
  424. package/web/assets/{cose-bilkent-RZA4XIPR-BHpK4Crp.js → cose-bilkent-Q72C2OJ3-DMeFXnK8.js} +1 -1
  425. package/web/assets/cynefin-OW5HDTMX-6OCTWOGG-vlqakYcO.js +1 -0
  426. package/web/assets/{cynefinDiagram-TR7LZUCG-C3Iar9lZ.js → cynefinDiagram-2OOWUY4M-BY6DZkTt.js} +1 -1
  427. package/web/assets/dagre-MPVFI544-DWO70fy_.js +4 -0
  428. package/web/assets/diagram-AE4NWXFW-f7JRVRUL.js +24 -0
  429. package/web/assets/{diagram-L7DVE3PN-GIRyVUtt.js → diagram-BUJID5UG-BXZv1rCS.js} +2 -2
  430. package/web/assets/{diagram-JCD7PQ7C-DC5-9FRr.js → diagram-C44CZ5NI-CRNfvjCq.js} +1 -1
  431. package/web/assets/diagram-EYOLEXXS-DZOjKQVE.js +30 -0
  432. package/web/assets/diagram-P7B6PWOJ-D3SQmw3_.js +3 -0
  433. package/web/assets/{ebnfDiagram-DRHRQJWO-D8_CI4ZF.js → ebnfDiagram-FTPZ3PV6-jKWpIDN2.js} +1 -1
  434. package/web/assets/erDiagram-H3ERR26V-BqJntEuJ.js +99 -0
  435. package/web/assets/eventmodeling-NTZA5JFV-WKSWQHFS-Bq4FqtBL.js +1 -0
  436. package/web/assets/flowDiagram-YHGXBVSY-Dnlk2bEu.js +1 -0
  437. package/web/assets/ganttDiagram-RWFTB7ED-Bl6Y1K5T.js +292 -0
  438. package/web/assets/gitGraph-4MIJSDKK-JH2HKYUO-B3yc4GkH.js +1 -0
  439. package/web/assets/gitGraphDiagram-MAR6GKOP-CkNvsrdw.js +106 -0
  440. package/web/assets/{index-CJDpyH-n.css → index-C2_aej58.css} +1 -1
  441. package/web/assets/{index-DDRie6_8.js → index-Dj3vQOHK.js} +51 -51
  442. package/web/assets/info-A6RAGUB7-3TX3OFWW-BM3N5_Dv.js +1 -0
  443. package/web/assets/infoDiagram-LV547AFH-COkFutAf.js +2 -0
  444. package/web/assets/{ishikawaDiagram-4JDSWWDM-DmqWtjkl.js → ishikawaDiagram-PUJQGNDS-Bb8FylSR.js} +2 -2
  445. package/web/assets/{journeyDiagram-QUS3FAKT-XAzVzrQW.js → journeyDiagram-EW5QJT4W-BzoHUBhM.js} +4 -4
  446. package/web/assets/{kanban-definition-D4L7SQKK-YurRnmYn.js → kanban-definition-JSQERAZB-Uy2Pi0yQ.js} +4 -4
  447. package/web/assets/katex-CZ4GXH2S-C0Fcou7U.js +257 -0
  448. package/web/assets/{mindmap-definition-66QP5TD6-ChrWWnil.js → mindmap-definition-VBJCLQLM-B-CnOnt_.js} +3 -3
  449. package/web/assets/packet-AYTQ26CC-MKII6P3Y-Bd52ZE3V.js +1 -0
  450. package/web/assets/{pegDiagram-YKIO5C6U-QGeQLEq2.js → pegDiagram-7WILOQTJ-D9sneKXg.js} +1 -1
  451. package/web/assets/pie-WAS4IAKB-6B4OPMJ5-DW5Xy69Z.js +1 -0
  452. package/web/assets/pieDiagram-EFA7CBSB-Dx2NQofL.js +39 -0
  453. package/web/assets/{quadrantDiagram-VO5QLCXA-B7098wSc.js → quadrantDiagram-WARVYA7P-DPKL9_0A.js} +3 -3
  454. package/web/assets/radar-RG4KPBEZ-UPTR3XUL-CkzibT2h.js +1 -0
  455. package/web/assets/railroad-74A4TZTK-MEFUPFMS-D9zF-mDN.js +1 -0
  456. package/web/assets/railroad-abnf-HS5TGJTU-R5YG2S5D-ruacjUbX.js +1 -0
  457. package/web/assets/railroad-ebnf-LZEXJU2U-G5QEX2L6-S1zc5OiO.js +1 -0
  458. package/web/assets/railroad-peg-WCYAUIDC-H5I2ZRY2-Cbcr0XzY.js +1 -0
  459. package/web/assets/{railroadDiagram-M77LTMSB-AXu4vxk_.js → railroadDiagram-5NIQVNLQ-DsweTo14.js} +1 -1
  460. package/web/assets/{requirementDiagram-RASO5HTO-B-l8InpK.js → requirementDiagram-SXREGOKZ-CXwdNSVR.js} +4 -4
  461. package/web/assets/{sankeyDiagram-F32LOJ6L-Kd7zjJgX.js → sankeyDiagram-VV74M2VP-CA6jtP9P.js} +3 -3
  462. package/web/assets/{sequenceDiagram-URATNSBD-BlcdY9DS.js → sequenceDiagram-52ZFIFDL-k_5rEbzm.js} +15 -15
  463. package/web/assets/src-Df5C1Nz4.js +1 -0
  464. package/web/assets/stateDiagram-3QAKPIVI-BejHTf31.js +1 -0
  465. package/web/assets/stateDiagram-v2-HN2P4RDZ-BrfoRuOc.js +1 -0
  466. package/web/assets/swimlanes-QLVP42QD-CQSVO5D6.js +1 -0
  467. package/web/assets/swimlanesDiagram-JKPDBFCN-DrWB9kcD.js +8 -0
  468. package/web/assets/{timeline-definition-WJXWRH4I-DUfp1R3E.js → timeline-definition-GS45XAXW-C0Ks8rPP.js} +4 -4
  469. package/web/assets/treeView-Q6P3EWNA-ZRJGANNQ-DmKOCo6L.js +1 -0
  470. package/web/assets/treemap-WGGIJYW6-K64VN5AS-DO3xY92U.js +1 -0
  471. package/web/assets/{vennDiagram-K3VCMQLI-Bj-FN-XS.js → vennDiagram-QIQU2ZRJ-rgPiS837.js} +3 -3
  472. package/web/assets/wardley-WFR3VGLG-D67OWCCH-DiDPBNft.js +1 -0
  473. package/web/assets/wardleyDiagram-U6YNM66N-DRVr7SPi.js +78 -0
  474. package/web/assets/{xychartDiagram-5VRUVLCW-CK_rbSWE.js → xychartDiagram-XJAZEDNM-COtlZzYb.js} +3 -3
  475. package/web/index.html +19 -17
  476. package/web/assets/ProcessFlowModal-Badh2Pbg.js +0 -24
  477. package/web/assets/architecture-TIHT7OUA-V6N4J3SY-fTePvLoe.js +0 -1
  478. package/web/assets/architectureDiagram-OT7VKSJ7-mKEXxkeF.js +0 -36
  479. package/web/assets/blockDiagram-54WLDVWM-Dg_hrRWE.js +0 -132
  480. package/web/assets/c4Diagram-X2LASM7V-CnhoT4aV.js +0 -10
  481. package/web/assets/chunk-2AEHWXPW-CV4r6-1I.js +0 -127
  482. package/web/assets/chunk-5VCL7Z4A-CQ-2dYWj.js +0 -1
  483. package/web/assets/chunk-6BELYETK-ChsYtfHW.js +0 -1
  484. package/web/assets/chunk-7CWYLC5S-DRgGkkpF.js +0 -2
  485. package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +0 -32
  486. package/web/assets/chunk-KRXBNO2N-C-UNuKKf.js +0 -1
  487. package/web/assets/chunk-LAHSG3N2-Bz4hcn0N.js +0 -321
  488. package/web/assets/chunk-LIEV3EAG-pyKGssV3.js +0 -1
  489. package/web/assets/chunk-NLANEA3F-XpH_NPA5.js +0 -62
  490. package/web/assets/chunk-PE7DX7ZZ-CCvRVj43.js +0 -10
  491. package/web/assets/chunk-Q67WD55A-BWCH2SVz.js +0 -156
  492. package/web/assets/chunk-SZD42YQK-ijyKKVr1.js +0 -70
  493. package/web/assets/chunk-TFPGFQPA-Dj6a-0pC.js +0 -231
  494. package/web/assets/chunk-TGVD4F4B-BMc31Gj2.js +0 -2
  495. package/web/assets/chunk-UAT7B5JY-DW-A_fpI.js +0 -1
  496. package/web/assets/chunk-VY5UBI4V-yxPQAWxw.js +0 -1
  497. package/web/assets/chunk-WJBAP47W-BckNkuEN.js +0 -1
  498. package/web/assets/classDiagram-VPOSVPXH-BjOiXA_C.js +0 -1
  499. package/web/assets/classDiagram-v2-5VFNUXQA-BjOiXA_C.js +0 -1
  500. package/web/assets/cynefin-VYW2F7L2-2VAHYKR6-DAsF6GZv.js +0 -1
  501. package/web/assets/dagre-K64A6Z3X-CUwi79mA.js +0 -4
  502. package/web/assets/diagram-2TLGJV2N-C2F5Nfym.js +0 -30
  503. package/web/assets/diagram-KFBZAVDW-Dfmf_4ti.js +0 -3
  504. package/web/assets/diagram-YP3FGXHI-CyNFYtkd.js +0 -24
  505. package/web/assets/erDiagram-SZLJLQMB-CohQjznC.js +0 -85
  506. package/web/assets/eventmodeling-45OFAUF4-AOUJWSLX-BvTc6iQi.js +0 -1
  507. package/web/assets/flowDiagram-BWE6NHOH-B6RnEvD9.js +0 -1
  508. package/web/assets/ganttDiagram-2QTCJSNI-Cks_mEcF.js +0 -292
  509. package/web/assets/gitGraph-TEB2WS4Q-U5VWYIBC-Dy7CCSZ5.js +0 -1
  510. package/web/assets/gitGraphDiagram-VVZAVV5G-CG41cIVc.js +0 -106
  511. package/web/assets/info-DKCQHKI2-DX6KST54-BLJg1ikX.js +0 -1
  512. package/web/assets/infoDiagram-FY4PZKRE-BJ3vPVwW.js +0 -2
  513. package/web/assets/katex-C5OPUE3Q-Bnbavtmu.js +0 -257
  514. package/web/assets/packet-7NZHBO7P-5WG45QPS-KUxcuvaA.js +0 -1
  515. package/web/assets/pie-RZYD4A2V-2OCZ2VTD-DPs08kJY.js +0 -1
  516. package/web/assets/pieDiagram-YPY3TKG5-BuT3MYzm.js +0 -39
  517. package/web/assets/radar-I7S5WNFK-EPLSA35B-w5F0K3a7.js +0 -1
  518. package/web/assets/railroad-3IZDKUUU-PWFQV6Y6-Bu668yqY.js +0 -1
  519. package/web/assets/railroad-abnf-AHOZXSZD-JYYJX3BS-B6ghpETS.js +0 -1
  520. package/web/assets/railroad-ebnf-EBAXGLYW-RBZ4ONAP-D-XmHh3M.js +0 -1
  521. package/web/assets/railroad-peg-LSFZ7HO6-KHNPXGPG-mhkrhzEn.js +0 -1
  522. package/web/assets/src-C5sx_gMp.js +0 -1
  523. package/web/assets/stateDiagram-DODFXNG5-DTdHc-fF.js +0 -1
  524. package/web/assets/stateDiagram-v2-JNMM5JRA-DioNLDDo.js +0 -1
  525. package/web/assets/swimlanes-OSWOYLSK-CA0ofdwY.js +0 -2
  526. package/web/assets/swimlanesDiagram-RHGX2RDE-PkwUdckC.js +0 -8
  527. package/web/assets/treeView-QDETBFTQ-EHYTSQNO-C5lpBgPm.js +0 -1
  528. package/web/assets/treemap-6X3UGDF4-CCWCF7EK-BB0ZyO-B.js +0 -1
  529. package/web/assets/wardley-OPB4EBWU-6OWERDVT-CEA3Nq0j.js +0 -1
  530. package/web/assets/wardleyDiagram-XK6FUAWV-CVV0dHFr.js +0 -78
  531. /package/web/assets/{sizeCapture-5GORAGP4-BEqQzsxs.js → sizeCapture-FGA5AGYP-BEqQzsxs.js} +0 -0
@@ -16,10 +16,10 @@
16
16
  import fs from 'fs/promises';
17
17
  import { realpathSync } from 'fs';
18
18
  import path from 'path';
19
- import os from 'os';
20
19
  import { getInferredRepoName, resolveRepoIdentityRoot, stripUrlCredentials } from './git.js';
21
20
  import { stripWindowsLongPathPrefix } from '../lib/utils.js';
22
21
  import { writeFileAtomic } from './fs-atomic.js';
22
+ import { getGlobalDir } from './global-dir.js';
23
23
  import { logger } from '../core/logger.js';
24
24
  import { acquireIndexLock, IndexLockTimeoutError } from './index-lock.js';
25
25
  import { branchSlug, BRANCHES_DIR, resolveBranchPlacement, } from './branch-index.js';
@@ -33,6 +33,7 @@ export { branchSlug, resolveBranchPlacement };
33
33
  // cycle that made the extraction necessary. `LEGACY_METADATA_FILE` and
34
34
  // `tryReadMetaFile` stay module-private here, exactly as before.
35
35
  export { getStoragePath, INDEX_METADATA_FILE, isMissingFilesystemError, loadMeta };
36
+ export { getGlobalDir } from './global-dir.js';
36
37
  /**
37
38
  * Normalise a repo path for registry comparison across platforms
38
39
  * (#664 review feedback from @evander-wang).
@@ -436,12 +437,6 @@ const ensureGitInfoExclude = async (repoPath) => {
436
437
  }
437
438
  };
438
439
  // ─── Global Registry (~/.gitnexus/registry.json) ───────────────────────
439
- /**
440
- * Get the path to the global GitNexus directory
441
- */
442
- export const getGlobalDir = () => {
443
- return process.env.GITNEXUS_HOME || path.join(os.homedir(), '.gitnexus');
444
- };
445
440
  /**
446
441
  * Get the path to the global registry file
447
442
  */
@@ -478,11 +473,9 @@ const REGISTRY_LOCK_TIMEOUT_MS = 5_000;
478
473
  * registry-private lock namespace; the handle is kernel-owned on supported
479
474
  * platforms and crash-reclaimable by the existing fallback.
480
475
  *
481
- * On timeout the transaction proceeds UNLOCKED rather than throwing: the lock
482
- * closes a lost-update race that existed unguarded before #2716, so degrading
483
- * to the old best-effort behaviour is strictly better than failing an
484
- * `analyze`/`list`/`augment` outright on a wedged lock (a stale pid-reuse
485
- * ghost on platforms without start-time verification can look live forever).
476
+ * On timeout the transaction fails closed: continuing unlocked would reintroduce
477
+ * the lost-update race this lock exists to prevent and can silently discard a
478
+ * concurrent registration.
486
479
  */
487
480
  const withRegistryLock = async (operation) => {
488
481
  let lock = null;
@@ -496,9 +489,10 @@ const withRegistryLock = async (operation) => {
496
489
  });
497
490
  }
498
491
  catch (err) {
499
- if (!(err instanceof IndexLockTimeoutError))
500
- throw err;
501
- logger.warn({ timeoutMs: REGISTRY_LOCK_TIMEOUT_MS }, 'Timed out waiting for the global registry lock; proceeding without it. A concurrent registry write may be lost.');
492
+ if (err instanceof IndexLockTimeoutError) {
493
+ logger.error({ timeoutMs: REGISTRY_LOCK_TIMEOUT_MS }, 'Timed out waiting for the global registry lock; refusing an unlocked registry transaction.');
494
+ }
495
+ throw err;
502
496
  }
503
497
  try {
504
498
  return await operation();
@@ -666,14 +660,11 @@ export const readRegistryStrict = async () => readRegistryFile(true);
666
660
  * Atomic tmp+rename: a crash mid-write can never leave a truncated
667
661
  * registry.json that the next load would treat as empty and silently drop
668
662
  * every registered repo (#2106 R9). The tmp path must stay per-write — the
669
- * registry is the one file every gitnexus process on the machine writes, and
670
- * `withRegistryLock` degrades to unlocked on timeout, so the write cannot rely
671
- * on the lock to keep two writers off one staging path (#2888).
672
- *
673
- * `attempts` is forwarded to the rename retry; best-effort callers pass `1`.
663
+ * registry is the one file every gitnexus process on the machine writes (#2888).
674
664
  */
675
665
  const writeRegistry = async (entries, attempts) => {
676
- await fs.mkdir(getGlobalDir(), { recursive: true });
666
+ const dir = getGlobalDir();
667
+ await fs.mkdir(dir, { recursive: true });
677
668
  await writeFileAtomic(getGlobalRegistryPath(), JSON.stringify(sanitizeEntries(entries), null, 2), attempts);
678
669
  };
679
670
  /**
@@ -771,7 +762,10 @@ const registerRepoUnlocked = async (repoPath, meta, opts) => {
771
762
  // expands macOS /var → /private/var and Windows 8.3 → long-name,
772
763
  // falling back to `path.resolve` when the path doesn't exist.
773
764
  const canonicalInput = canonicalizePath(repoPath);
774
- const entries = await readRegistry();
765
+ // Mutating writes must not treat an unreadable/truncated registry as empty
766
+ // (#3094): lenient `readRegistry()` returns `[]` on parse failure and would
767
+ // replace the machine-wide file with only this entry. ENOENT stays empty.
768
+ const entries = await readRegistryStrict();
775
769
  const existingIdx = entries.findIndex((e) => {
776
770
  // Canonicalise the STORED entry too so pre-canonicalisation
777
771
  // registries (written by older versions, or paths passed in a
@@ -881,7 +875,7 @@ const registerRepoUnlocked = async (repoPath, meta, opts) => {
881
875
  // R9): re-derive THIS run's delta against the FRESHEST snapshot so a
882
876
  // concurrent change to the OTHER axis (a branch upsert vs a primary refresh)
883
877
  // survives instead of being clobbered by a stale entry-time view.
884
- const fresh = await readRegistry();
878
+ const fresh = await readRegistryStrict();
885
879
  const freshIdx = fresh.findIndex((e) => {
886
880
  const a = canonicalizePath(e.path);
887
881
  return registryPathEquals(a, canonicalInput);
@@ -1301,6 +1295,24 @@ export const resolveRegistryEntry = (entries, target) => {
1301
1295
  const availableNames = entries.map((e) => (nameCounts.get(e.name.toLowerCase()) ?? 0) > 1 ? `${e.name} (${e.path})` : e.name);
1302
1296
  throw new RegistryNotFoundError(target, availableNames);
1303
1297
  };
1298
+ /**
1299
+ * Name-only registry match (the name tier of {@link resolveRegistryEntry},
1300
+ * without path matching). Used by `group.yaml` member *values*, which are
1301
+ * registry aliases, not filesystem paths.
1302
+ *
1303
+ * Zero matches → `undefined` (caller treats as missing). One match → that
1304
+ * entry. Two or more → {@link RegistryAmbiguousTargetError}.
1305
+ */
1306
+ export const findRegistryEntryByName = (entries, name) => {
1307
+ const targetLower = name.toLowerCase();
1308
+ const nameMatches = entries.filter((e) => e.name.toLowerCase() === targetLower);
1309
+ if (nameMatches.length === 1)
1310
+ return nameMatches[0];
1311
+ if (nameMatches.length > 1) {
1312
+ throw new RegistryAmbiguousTargetError(name, nameMatches);
1313
+ }
1314
+ return undefined;
1315
+ };
1304
1316
  /**
1305
1317
  * List all registered repos from the global registry.
1306
1318
  *
@@ -1374,8 +1386,6 @@ export const listRegisteredRepos = async (opts) => {
1374
1386
  try {
1375
1387
  await withRegistryLock(async () => {
1376
1388
  const fresh = await readRegistry();
1377
- // attempts: 1 — the catch below discards a failure, so the rename
1378
- // backoff would only make every other process wait out this lock.
1379
1389
  await writeRegistry(fresh.filter((entry) => !pruned.has(entry.path)), 1);
1380
1390
  });
1381
1391
  }
@@ -78,6 +78,35 @@ export interface RepoMeta {
78
78
  repoPath: string;
79
79
  lastCommit: string;
80
80
  indexedAt: string;
81
+ /**
82
+ * Runtime enrichment mode plus redacted scan exclusions. Payload data and
83
+ * absolute/external paths are deliberately excluded from metadata.
84
+ */
85
+ springActuator?: {
86
+ enabled: boolean;
87
+ /**
88
+ * Normalized repo-relative inputs that must remain excluded from all future
89
+ * source scans. The list is empty when every configured input was external.
90
+ */
91
+ repoRelativeInputs: string[];
92
+ };
93
+ /**
94
+ * Whether the index was built with AsyncAPI document reading enabled.
95
+ *
96
+ * Only the FLAG is recorded, unlike `springActuator` above, because the two
97
+ * options need different things from this field. Actuator inputs are retained
98
+ * so future scans keep excluding them; documents are deliberately NOT
99
+ * excluded from scanning — a committed one wants its real `File` node — so
100
+ * there is nothing to retain, and recording the configured path would put an
101
+ * operator's absolute directory layout into index metadata for no consumer.
102
+ *
103
+ * The flag alone is what the disable transition needs: without it, dropping
104
+ * the option leaves document-derived destinations in an index with nothing
105
+ * able to notice they should go.
106
+ */
107
+ asyncApiSpec?: {
108
+ enabled: boolean;
109
+ };
81
110
  /**
82
111
  * Analyzer/runtime receipt for the successful run represented by this
83
112
  * metadata. Optional so indexes written by older GitNexus releases remain
@@ -185,6 +214,11 @@ export interface RepoMeta {
185
214
  * containing relevant source files.
186
215
  */
187
216
  analysisFeatures?: Record<string, number>;
217
+ /**
218
+ * Canonical registered-prefix list used to resolve vendor Spring mapping
219
+ * annotations. A changed value invalidates persisted JVM Route evidence.
220
+ */
221
+ springVendorPrefixes?: string;
188
222
  /**
189
223
  * The resolved GITNEXUS_FTS_CJK_SEGMENTATION mode ('none' | 'bigram') the
190
224
  * existing index's content/description columns were last written under
@@ -0,0 +1,48 @@
1
+ /** Envelope version — independent of PARSE_CACHE_VERSION / SCHEMA_BUMP. */
2
+ export declare const V8_CACHE_FORMAT = 5;
3
+ /**
4
+ * Collapse duplicate strings in a live deserialized graph into `pool`, mutating
5
+ * in place so object identity (shared `SymbolDefinition`s, Maps) is preserved.
6
+ * Required after `v8.deserialize` of ParsedFile shards: V8 does not recreate
7
+ * the JSON reviver's cross-shard string intern, and skipping it regresses
8
+ * retained heap (~+59% measured vs interned JSON).
9
+ */
10
+ export declare const internGraphStrings: (root: unknown, pool: Map<string, string>) => unknown;
11
+ /** NDJSON listing cannot encode paths that themselves contain CR/LF/NUL. */
12
+ export declare const encodeCachePathListing: (paths: readonly string[]) => Buffer;
13
+ /**
14
+ * Parse a counted NDJSON path listing. Returns `null` when it must not be
15
+ * trusted to skip the payload: missing trailing newline, CR/NUL, or a count
16
+ * that does not match the remaining lines.
17
+ */
18
+ export declare const parseCachePathListing: (raw: Buffer) => string[] | null;
19
+ export type V8CacheHit = {
20
+ kind: 'hit';
21
+ value: unknown;
22
+ bytes: number;
23
+ };
24
+ export type V8CacheSkip = {
25
+ kind: 'skip';
26
+ bytes: number;
27
+ };
28
+ export type V8CacheLoad = V8CacheHit | V8CacheSkip;
29
+ export type V8CacheInspection = {
30
+ paths: readonly string[];
31
+ };
32
+ /**
33
+ * Validate the immutable envelope metadata needed by the durable ParsedFile
34
+ * warm-hit gate without deserializing its payload. Atomic publication means a
35
+ * runtime-compatible envelope whose exact file length and counted path listing
36
+ * validate is a stable snapshot candidate; malformed/truncated envelopes miss.
37
+ */
38
+ export declare const inspectV8Cache: (filePath: string) => Promise<V8CacheInspection | undefined>;
39
+ /**
40
+ * Load a cache file. When `wantPaths` is set and a digest-verified non-empty
41
+ * path listing has no intersection, returns `{ kind: 'skip' }` without
42
+ * deserializing. An authentic listing that does not parse deserializes (fail
43
+ * closed). Envelope/runtime/digest failure returns undefined (miss).
44
+ */
45
+ export declare const tryLoadV8Cache: (filePath: string, internPool?: Map<string, string>, wantPaths?: ReadonlySet<string>) => Promise<V8CacheLoad | undefined>;
46
+ export declare const writeV8CacheFile: (filePath: string, graph: unknown, paths?: readonly string[]) => Promise<boolean>;
47
+ export declare const writeV8CacheFileSync: (filePath: string, graph: unknown, paths?: readonly string[]) => boolean;
48
+ export declare const copyV8CacheIfPresent: (srcPath: string, dstPath: string) => Promise<boolean>;
@@ -0,0 +1,347 @@
1
+ /**
2
+ * One-file V8 cache envelope for parse-cache and ParsedFile shards.
3
+ *
4
+ * Each object-graph shard is a single immutable `.v8` file published by
5
+ * tmp+rename. JSON is not a fallback: a missing, corrupt, runtime-incompatible,
6
+ * or deserialize-failed envelope is a cache miss (re-extract / re-dispatch).
7
+ * Tiny JSON manifests (`index.json`) stay outside this module.
8
+ *
9
+ * Envelope: magic, format, Node major, V8 version, optional path listing,
10
+ * `v8.serialize` of the live graph, then SHA-256 of listing||payload. Path
11
+ * bytes live before the payload so a ParsedFile loader can skip a shard whose
12
+ * authenticated listing misses `wantPaths` without deserializing. An
13
+ * unreadable/invalid listing is fail-closed: deserialize, never skip.
14
+ */
15
+ import { promises as fs } from 'node:fs';
16
+ import { createHash } from 'node:crypto';
17
+ import v8 from 'node:v8';
18
+ import { logger } from '../core/logger.js';
19
+ import { linkOrCopyFile, writeFileAtomicBytes, writeFileAtomicBytesSync } from './fs-atomic.js';
20
+ const MAGIC = Buffer.from('GNXV8CF1', 'ascii');
21
+ /** Envelope version — independent of PARSE_CACHE_VERSION / SCHEMA_BUMP. */
22
+ export const V8_CACHE_FORMAT = 5;
23
+ const U32 = 4;
24
+ const U16 = 2;
25
+ const PAYLOAD_HASH_LEN = 32;
26
+ const MAGIC_LEN = 8;
27
+ const FIXED_PREFIX = MAGIC_LEN + U32 + U16 + U16; // magic + format + nodeMajor + v8len
28
+ const internString = (value, pool) => {
29
+ const hit = pool.get(value);
30
+ if (hit !== undefined)
31
+ return hit;
32
+ pool.set(value, value);
33
+ return value;
34
+ };
35
+ /**
36
+ * Collapse duplicate strings in a live deserialized graph into `pool`, mutating
37
+ * in place so object identity (shared `SymbolDefinition`s, Maps) is preserved.
38
+ * Required after `v8.deserialize` of ParsedFile shards: V8 does not recreate
39
+ * the JSON reviver's cross-shard string intern, and skipping it regresses
40
+ * retained heap (~+59% measured vs interned JSON).
41
+ */
42
+ export const internGraphStrings = (root, pool) => {
43
+ const seen = new WeakSet();
44
+ const walk = (value) => {
45
+ if (typeof value === 'string')
46
+ return internString(value, pool);
47
+ if (value === null || typeof value !== 'object')
48
+ return value;
49
+ if (ArrayBuffer.isView(value) || value instanceof ArrayBuffer)
50
+ return value;
51
+ if (seen.has(value))
52
+ return value;
53
+ seen.add(value);
54
+ if (value instanceof Map) {
55
+ const entries = [...value];
56
+ value.clear();
57
+ for (const [k, v] of entries)
58
+ value.set(walk(k), walk(v));
59
+ return value;
60
+ }
61
+ if (value instanceof Set) {
62
+ const entries = [...value];
63
+ value.clear();
64
+ for (const v of entries)
65
+ value.add(walk(v));
66
+ return value;
67
+ }
68
+ if (Array.isArray(value)) {
69
+ for (let i = 0; i < value.length; i++)
70
+ value[i] = walk(value[i]);
71
+ return value;
72
+ }
73
+ const rec = value;
74
+ for (const key of Object.keys(rec)) {
75
+ rec[key] = walk(rec[key]);
76
+ }
77
+ return value;
78
+ };
79
+ return walk(root);
80
+ };
81
+ const nodeMajor = () => Number.parseInt(process.versions.node.split('.')[0] ?? '0', 10);
82
+ const isEnoent = (err) => err.code === 'ENOENT';
83
+ const warnCache = (err, filePath, msg) => {
84
+ logger.warn({ err, filePath }, msg);
85
+ };
86
+ /** NDJSON listing cannot encode paths that themselves contain CR/LF/NUL. */
87
+ export const encodeCachePathListing = (paths) => {
88
+ if (paths.length === 0)
89
+ return Buffer.alloc(0);
90
+ if (paths.some((p) => /[\r\n\0]/.test(p)))
91
+ return Buffer.alloc(0);
92
+ return Buffer.from(`${paths.length}\n${paths.join('\n')}\n`, 'utf8');
93
+ };
94
+ /**
95
+ * Parse a counted NDJSON path listing. Returns `null` when it must not be
96
+ * trusted to skip the payload: missing trailing newline, CR/NUL, or a count
97
+ * that does not match the remaining lines.
98
+ */
99
+ export const parseCachePathListing = (raw) => {
100
+ if (raw.byteLength === 0)
101
+ return [];
102
+ let sidecarRaw;
103
+ try {
104
+ sidecarRaw = new TextDecoder('utf-8', { fatal: true }).decode(raw);
105
+ }
106
+ catch {
107
+ return null;
108
+ }
109
+ if (sidecarRaw.includes('\0') || sidecarRaw.includes('\r') || !sidecarRaw.endsWith('\n')) {
110
+ return null;
111
+ }
112
+ const nl = sidecarRaw.indexOf('\n');
113
+ if (nl < 0)
114
+ return null;
115
+ const countToken = sidecarRaw.slice(0, nl);
116
+ if (!/^[0-9]+$/.test(countToken))
117
+ return null;
118
+ const count = Number(countToken);
119
+ const body = sidecarRaw.slice(nl + 1);
120
+ const listed = body === '' ? [] : body.slice(0, -1).split('\n');
121
+ if (listed.length !== count)
122
+ return null;
123
+ return listed;
124
+ };
125
+ const encodeEnvelope = (graph, paths) => {
126
+ let payload;
127
+ try {
128
+ payload = v8.serialize(graph);
129
+ }
130
+ catch (err) {
131
+ warnCache(err, '', 'v8 cache: serialize failed; treating as miss on next load');
132
+ return undefined;
133
+ }
134
+ const pathListing = encodeCachePathListing(paths);
135
+ const listed = parseCachePathListing(pathListing);
136
+ const pathCount = listed === null ? 0 : listed.length;
137
+ if (payload.byteLength > 0xffff_ffff || pathListing.byteLength > 0xffff_ffff)
138
+ return undefined;
139
+ const v8ver = Buffer.from(process.versions.v8, 'utf8');
140
+ if (v8ver.byteLength > 0xffff)
141
+ return undefined;
142
+ const header = Buffer.allocUnsafe(FIXED_PREFIX + v8ver.length + U32 * 3);
143
+ MAGIC.copy(header, 0);
144
+ header.writeUInt32LE(V8_CACHE_FORMAT, MAGIC_LEN);
145
+ header.writeUInt16LE(nodeMajor(), MAGIC_LEN + U32);
146
+ header.writeUInt16LE(v8ver.length, MAGIC_LEN + U32 + U16);
147
+ v8ver.copy(header, FIXED_PREFIX);
148
+ let off = FIXED_PREFIX + v8ver.length;
149
+ header.writeUInt32LE(pathCount, off);
150
+ off += U32;
151
+ header.writeUInt32LE(pathListing.byteLength, off);
152
+ off += U32;
153
+ header.writeUInt32LE(payload.byteLength, off);
154
+ const payloadHash = createHash('sha256').update(pathListing).update(payload).digest();
155
+ return Buffer.concat([header, pathListing, payload, payloadHash]);
156
+ };
157
+ const decodePrefix = (buf) => {
158
+ if (buf.byteLength < FIXED_PREFIX)
159
+ return undefined;
160
+ if (!buf.subarray(0, MAGIC_LEN).equals(MAGIC))
161
+ return undefined;
162
+ if (buf.readUInt32LE(MAGIC_LEN) !== V8_CACHE_FORMAT)
163
+ return undefined;
164
+ const recordedNodeMajor = buf.readUInt16LE(MAGIC_LEN + U32);
165
+ const v8len = buf.readUInt16LE(MAGIC_LEN + U32 + U16);
166
+ const v8off = FIXED_PREFIX;
167
+ const countsOff = v8off + v8len;
168
+ if (buf.byteLength < countsOff + U32 * 3)
169
+ return undefined;
170
+ const recordedV8 = buf.subarray(v8off, v8off + v8len).toString('utf8');
171
+ const pathCount = buf.readUInt32LE(countsOff);
172
+ const pathBytes = buf.readUInt32LE(countsOff + U32);
173
+ const payloadLen = buf.readUInt32LE(countsOff + U32 * 2);
174
+ const pathsOff = countsOff + U32 * 3;
175
+ const payloadOff = pathsOff + pathBytes;
176
+ return {
177
+ recordedNodeMajor,
178
+ recordedV8,
179
+ pathCount,
180
+ pathBytes,
181
+ payloadLen,
182
+ pathsOff,
183
+ payloadOff,
184
+ };
185
+ };
186
+ const runtimeCompatible = (meta) => meta.recordedNodeMajor === nodeMajor() && meta.recordedV8 === process.versions.v8;
187
+ const readExact = async (fh, offset, length) => {
188
+ const buf = Buffer.allocUnsafe(length);
189
+ let got = 0;
190
+ while (got < length) {
191
+ const { bytesRead } = await fh.read(buf, got, length - got, offset + got);
192
+ if (bytesRead === 0)
193
+ return undefined;
194
+ got += bytesRead;
195
+ }
196
+ return buf;
197
+ };
198
+ const readVerifiedPayload = async (fh, meta, pathRaw) => {
199
+ const payloadAndHash = await readExact(fh, meta.payloadOff, meta.payloadLen + PAYLOAD_HASH_LEN);
200
+ if (!payloadAndHash)
201
+ return undefined;
202
+ const payload = payloadAndHash.subarray(0, meta.payloadLen);
203
+ const expected = payloadAndHash.subarray(meta.payloadLen);
204
+ const digest = createHash('sha256').update(pathRaw).update(payload).digest();
205
+ return digest.equals(expected) ? payload : undefined;
206
+ };
207
+ /**
208
+ * Validate the immutable envelope metadata needed by the durable ParsedFile
209
+ * warm-hit gate without deserializing its payload. Atomic publication means a
210
+ * runtime-compatible envelope whose exact file length and counted path listing
211
+ * validate is a stable snapshot candidate; malformed/truncated envelopes miss.
212
+ */
213
+ export const inspectV8Cache = async (filePath) => {
214
+ let fh;
215
+ try {
216
+ fh = await fs.open(filePath, 'r');
217
+ const st = await fh.stat();
218
+ const prefix = await readExact(fh, 0, Math.min(st.size, FIXED_PREFIX + 256 + U32 * 3));
219
+ if (!prefix)
220
+ return undefined;
221
+ const meta = decodePrefix(prefix);
222
+ if (!meta || !runtimeCompatible(meta))
223
+ return undefined;
224
+ if (meta.payloadOff + meta.payloadLen + PAYLOAD_HASH_LEN !== st.size || meta.pathBytes === 0) {
225
+ return undefined;
226
+ }
227
+ const pathRaw = prefix.byteLength >= meta.payloadOff
228
+ ? Buffer.from(prefix.subarray(meta.pathsOff, meta.payloadOff))
229
+ : await readExact(fh, meta.pathsOff, meta.pathBytes);
230
+ if (!pathRaw)
231
+ return undefined;
232
+ const listed = parseCachePathListing(pathRaw);
233
+ if (listed === null || listed.length !== meta.pathCount || listed.length === 0) {
234
+ return undefined;
235
+ }
236
+ if (!(await readVerifiedPayload(fh, meta, pathRaw)))
237
+ return undefined;
238
+ return { paths: listed };
239
+ }
240
+ catch (err) {
241
+ if (!isEnoent(err)) {
242
+ logger.debug({ err, filePath }, 'v8 cache: inspection failed; treating as miss');
243
+ }
244
+ return undefined;
245
+ }
246
+ finally {
247
+ await fh?.close().catch(() => { });
248
+ }
249
+ };
250
+ /**
251
+ * Load a cache file. When `wantPaths` is set and a digest-verified non-empty
252
+ * path listing has no intersection, returns `{ kind: 'skip' }` without
253
+ * deserializing. An authentic listing that does not parse deserializes (fail
254
+ * closed). Envelope/runtime/digest failure returns undefined (miss).
255
+ */
256
+ export const tryLoadV8Cache = async (filePath, internPool, wantPaths) => {
257
+ let fh;
258
+ try {
259
+ fh = await fs.open(filePath, 'r');
260
+ const st = await fh.stat();
261
+ const prefix = await readExact(fh, 0, Math.min(st.size, FIXED_PREFIX + 256 + U32 * 3));
262
+ if (!prefix)
263
+ return undefined;
264
+ const meta = decodePrefix(prefix);
265
+ if (!meta)
266
+ return undefined;
267
+ if (!runtimeCompatible(meta))
268
+ return undefined;
269
+ if (meta.payloadOff + meta.payloadLen + PAYLOAD_HASH_LEN !== st.size)
270
+ return undefined;
271
+ let pathRaw = Buffer.alloc(0);
272
+ if (meta.pathBytes > 0) {
273
+ if (prefix.byteLength >= meta.payloadOff) {
274
+ pathRaw = Buffer.from(prefix.subarray(meta.pathsOff, meta.payloadOff));
275
+ }
276
+ else {
277
+ const raw = await readExact(fh, meta.pathsOff, meta.pathBytes);
278
+ if (!raw)
279
+ return undefined;
280
+ pathRaw = Buffer.from(raw);
281
+ }
282
+ }
283
+ const payload = await readVerifiedPayload(fh, meta, pathRaw);
284
+ if (!payload)
285
+ return undefined;
286
+ if (wantPaths && wantPaths.size > 0 && meta.pathBytes > 0) {
287
+ const listed = parseCachePathListing(pathRaw);
288
+ if (listed !== null &&
289
+ listed.length === meta.pathCount &&
290
+ listed.length > 0 &&
291
+ !listed.some((p) => wantPaths.has(p))) {
292
+ return { kind: 'skip', bytes: st.size };
293
+ }
294
+ }
295
+ const value = v8.deserialize(payload);
296
+ if (internPool)
297
+ internGraphStrings(value, internPool);
298
+ return { kind: 'hit', value, bytes: st.size };
299
+ }
300
+ catch (err) {
301
+ if (!isEnoent(err)) {
302
+ logger.debug({ err, filePath }, 'v8 cache: load failed; treating as miss');
303
+ }
304
+ return undefined;
305
+ }
306
+ finally {
307
+ await fh?.close().catch(() => { });
308
+ }
309
+ };
310
+ export const writeV8CacheFile = async (filePath, graph, paths) => {
311
+ const blob = encodeEnvelope(graph, paths ?? []);
312
+ if (!blob)
313
+ return false;
314
+ try {
315
+ await writeFileAtomicBytes(filePath, blob, 1);
316
+ return true;
317
+ }
318
+ catch (err) {
319
+ warnCache(err, filePath, 'v8 cache: write failed; treating as miss');
320
+ return false;
321
+ }
322
+ };
323
+ export const writeV8CacheFileSync = (filePath, graph, paths) => {
324
+ const blob = encodeEnvelope(graph, paths ?? []);
325
+ if (!blob)
326
+ return false;
327
+ try {
328
+ writeFileAtomicBytesSync(filePath, blob);
329
+ return true;
330
+ }
331
+ catch (err) {
332
+ warnCache(err, filePath, 'v8 cache: write failed; treating as miss');
333
+ return false;
334
+ }
335
+ };
336
+ export const copyV8CacheIfPresent = async (srcPath, dstPath) => {
337
+ try {
338
+ await linkOrCopyFile(srcPath, dstPath);
339
+ return true;
340
+ }
341
+ catch (copyErr) {
342
+ if (!isEnoent(copyErr)) {
343
+ warnCache(copyErr, srcPath, 'v8 cache: copy failed; treating as miss');
344
+ }
345
+ return false;
346
+ }
347
+ };
@@ -13,6 +13,18 @@ export interface PipelineResult {
13
13
  totalFileCount: number;
14
14
  communityResult?: CommunityDetectionResult;
15
15
  processResult?: ProcessDetectionResult;
16
+ /**
17
+ * Runs the community/process phases that `skipDerivedGraphPhases` held back
18
+ * (#3016), against the same graph and phase outputs the pipeline already
19
+ * produced, and populates `communityResult`/`processResult` on this object.
20
+ *
21
+ * Present ONLY when those phases were skipped for that reason, so a caller
22
+ * that optimistically skipped them can still get a byte-identical derived
23
+ * layer on the paths that turn out to need one (full rebuild, escalated
24
+ * write, or an incremental run with deleted files). Absent means the phases
25
+ * either already ran or were disabled for an unrelated reason.
26
+ */
27
+ runDeferredDerivedPhases?: () => Promise<void>;
16
28
  /**
17
29
  * Additive diagnostics for registry-primary resolution decisions that
18
30
  * deliberately suppress edge emission. Empty means no diagnostic was
@@ -40,6 +52,8 @@ export interface PipelineResult {
40
52
  usedWorkerPool: boolean;
41
53
  /** Files actually dispatched to parser workers after parse-cache lookup. */
42
54
  reparsedFileCount: number;
55
+ /** Files restored from parse-cache chunks without parser-worker dispatch. */
56
+ parseCacheHitFileCount?: number;
43
57
  /** Files omitted from scope-resolution while the rest of analysis continued. */
44
58
  scopeExtractionFailures: readonly string[];
45
59
  /** Files scope resolution could not inspect because their parser was unavailable. */
@@ -0,0 +1,2 @@
1
+ export declare function isProcessAlive(pid: number): boolean;
2
+ export declare function readProcessStartTime(pid: number): string | undefined;
@@ -0,0 +1,35 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ export function isProcessAlive(pid) {
3
+ try {
4
+ process.kill(pid, 0);
5
+ return true;
6
+ }
7
+ catch (error) {
8
+ return error.code !== 'ESRCH';
9
+ }
10
+ }
11
+ export function readProcessStartTime(pid) {
12
+ try {
13
+ const startedAt = process.platform === 'win32'
14
+ ? execFileSync('powershell.exe', [
15
+ '-NoProfile',
16
+ '-NonInteractive',
17
+ '-Command',
18
+ `$p = Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}"; if ($p) { $p.CreationDate.ToUniversalTime().ToString("O") }`,
19
+ ], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
20
+ : // `lstart` is rendered through localtime and the active locale, so the
21
+ // same live process yields a different string under a different TZ or
22
+ // LC_TIME. That string is a lock owner's identity, and a mismatch is
23
+ // read as PID reuse — an unpinned render lets one daemon reclaim a
24
+ // mutex another still holds. Pin both so the identity is absolute.
25
+ execFileSync('ps', ['-p', String(pid), '-o', 'lstart='], {
26
+ encoding: 'utf-8',
27
+ stdio: ['ignore', 'pipe', 'ignore'],
28
+ env: { ...process.env, TZ: 'UTC', LC_ALL: 'C' },
29
+ }).trim();
30
+ return startedAt || undefined;
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }