gitnexus 1.6.9 → 1.6.10-aptos.0

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 (539) hide show
  1. package/README.md +211 -53
  2. package/dist/_shared/graph/types.d.ts +67 -3
  3. package/dist/_shared/graph/types.d.ts.map +1 -1
  4. package/dist/_shared/index.d.ts +1 -0
  5. package/dist/_shared/index.d.ts.map +1 -1
  6. package/dist/_shared/index.js.map +1 -1
  7. package/dist/_shared/integrations/resilient-fetch.d.ts +3 -1
  8. package/dist/_shared/integrations/resilient-fetch.d.ts.map +1 -1
  9. package/dist/_shared/integrations/resilient-fetch.js +4 -3
  10. package/dist/_shared/integrations/resilient-fetch.js.map +1 -1
  11. package/dist/_shared/language-detection.d.ts.map +1 -1
  12. package/dist/_shared/language-detection.js +2 -0
  13. package/dist/_shared/language-detection.js.map +1 -1
  14. package/dist/_shared/languages.d.ts +2 -0
  15. package/dist/_shared/languages.d.ts.map +1 -1
  16. package/dist/_shared/languages.js +2 -0
  17. package/dist/_shared/languages.js.map +1 -1
  18. package/dist/_shared/lbug/schema-constants.d.ts +2 -2
  19. package/dist/_shared/lbug/schema-constants.d.ts.map +1 -1
  20. package/dist/_shared/lbug/schema-constants.js +8 -0
  21. package/dist/_shared/lbug/schema-constants.js.map +1 -1
  22. package/dist/_shared/pipeline.d.ts +1 -1
  23. package/dist/_shared/pipeline.d.ts.map +1 -1
  24. package/dist/_shared/scope-resolution/callable-flow-site.d.ts +110 -0
  25. package/dist/_shared/scope-resolution/callable-flow-site.d.ts.map +1 -0
  26. package/dist/_shared/scope-resolution/callable-flow-site.js +11 -0
  27. package/dist/_shared/scope-resolution/callable-flow-site.js.map +1 -0
  28. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts +1 -1
  29. package/dist/_shared/scope-resolution/finalize-algorithm.d.ts.map +1 -1
  30. package/dist/_shared/scope-resolution/finalize-algorithm.js +1 -1
  31. package/dist/_shared/scope-resolution/finalize-algorithm.js.map +1 -1
  32. package/dist/_shared/scope-resolution/language-classification.d.ts.map +1 -1
  33. package/dist/_shared/scope-resolution/language-classification.js +1 -0
  34. package/dist/_shared/scope-resolution/language-classification.js.map +1 -1
  35. package/dist/_shared/scope-resolution/parsed-file.d.ts +7 -0
  36. package/dist/_shared/scope-resolution/parsed-file.d.ts.map +1 -1
  37. package/dist/_shared/scope-resolution/reference-site.d.ts +9 -1
  38. package/dist/_shared/scope-resolution/reference-site.d.ts.map +1 -1
  39. package/dist/_shared/scope-resolution/types.d.ts +20 -3
  40. package/dist/_shared/scope-resolution/types.d.ts.map +1 -1
  41. package/dist/cli/ai-context.d.ts +1 -1
  42. package/dist/cli/ai-context.js +25 -44
  43. package/dist/cli/analyze.d.ts +5 -2
  44. package/dist/cli/analyze.js +197 -11
  45. package/dist/cli/clean.js +17 -3
  46. package/dist/cli/cli-message.d.ts +1 -1
  47. package/dist/cli/doctor.d.ts +18 -0
  48. package/dist/cli/doctor.js +96 -5
  49. package/dist/cli/editor-targets.d.ts +17 -2
  50. package/dist/cli/editor-targets.js +44 -0
  51. package/dist/cli/embeddings.d.ts +12 -0
  52. package/dist/cli/embeddings.js +49 -0
  53. package/dist/cli/eval-server.d.ts +23 -1
  54. package/dist/cli/eval-server.js +126 -8
  55. package/dist/cli/help-i18n.js +6 -0
  56. package/dist/cli/i18n/en.d.ts +18 -8
  57. package/dist/cli/i18n/en.js +18 -8
  58. package/dist/cli/i18n/resources.d.ts +28 -8
  59. package/dist/cli/i18n/zh-CN.d.ts +10 -0
  60. package/dist/cli/i18n/zh-CN.js +18 -8
  61. package/dist/cli/index.js +21 -7
  62. package/dist/cli/lazy-action.d.ts +7 -0
  63. package/dist/cli/lazy-action.js +27 -0
  64. package/dist/cli/mcp.js +6 -3
  65. package/dist/cli/move-availability.d.ts +5 -0
  66. package/dist/cli/move-availability.js +11 -0
  67. package/dist/cli/setup.d.ts +8 -0
  68. package/dist/cli/setup.js +230 -32
  69. package/dist/cli/skill-gen.js +38 -18
  70. package/dist/cli/standard-skills.d.ts +76 -0
  71. package/dist/cli/standard-skills.js +45 -0
  72. package/dist/cli/status.d.ts +4 -1
  73. package/dist/cli/status.js +57 -4
  74. package/dist/cli/tool.js +11 -0
  75. package/dist/cli/uninstall.js +77 -18
  76. package/dist/cli/wiki.d.ts +1 -0
  77. package/dist/cli/wiki.js +7 -1
  78. package/dist/config/ignore-service.d.ts +2 -0
  79. package/dist/config/ignore-service.js +27 -0
  80. package/dist/core/analysis-features.d.ts +21 -0
  81. package/dist/core/analysis-features.js +59 -0
  82. package/dist/core/analyzer-identity.d.ts +74 -0
  83. package/dist/core/analyzer-identity.js +1820 -0
  84. package/dist/core/augmentation/engine.js +13 -8
  85. package/dist/core/embeddings/embedder.d.ts +3 -2
  86. package/dist/core/embeddings/embedder.js +24 -7
  87. package/dist/core/embeddings/embedding-identity.d.ts +11 -0
  88. package/dist/core/embeddings/embedding-identity.js +24 -0
  89. package/dist/core/embeddings/embedding-pipeline.d.ts +36 -1
  90. package/dist/core/embeddings/embedding-pipeline.js +100 -9
  91. package/dist/core/embeddings/http-client.d.ts +33 -3
  92. package/dist/core/embeddings/http-client.js +237 -25
  93. package/dist/core/embeddings/node-module-compat.d.ts +25 -0
  94. package/dist/core/embeddings/node-module-compat.js +25 -0
  95. package/dist/core/embeddings/onnxruntime-common-resolver.js +8 -5
  96. package/dist/core/embeddings/onnxruntime-node-resolver.js +33 -7
  97. package/dist/core/embeddings/runtime-install.d.ts +119 -0
  98. package/dist/core/embeddings/runtime-install.js +372 -0
  99. package/dist/core/embeddings/runtime-support.d.ts +48 -17
  100. package/dist/core/embeddings/runtime-support.js +96 -0
  101. package/dist/core/git-staleness.js +1 -1
  102. package/dist/core/group/bridge-db.js +2 -0
  103. package/dist/core/group/extractors/http-patterns/python.js +246 -108
  104. package/dist/core/group/extractors/manifest-extractor.js +4 -0
  105. package/dist/core/incremental/escalation-gate.d.ts +38 -0
  106. package/dist/core/incremental/escalation-gate.js +48 -0
  107. package/dist/core/incremental/shadow-candidates.d.ts +3 -3
  108. package/dist/core/incremental/shadow-candidates.js +3 -3
  109. package/dist/core/incremental/subgraph-extract.d.ts +2 -2
  110. package/dist/core/incremental/subgraph-extract.js +2 -2
  111. package/dist/core/index-freshness.d.ts +5 -0
  112. package/dist/core/index-freshness.js +13 -0
  113. package/dist/core/ingestion/class-extractors/configs/jvm.js +29 -0
  114. package/dist/core/ingestion/cobol/cobol-preprocessor.js +1 -1
  115. package/dist/core/ingestion/cobol/jcl-processor.js +9 -8
  116. package/dist/core/ingestion/cobol-processor.js +27 -26
  117. package/dist/core/ingestion/community-processor.d.ts +51 -1
  118. package/dist/core/ingestion/community-processor.js +323 -64
  119. package/dist/core/ingestion/emit-references.js +7 -2
  120. package/dist/core/ingestion/filesystem-walker.js +4 -0
  121. package/dist/core/ingestion/frameworks/spring/analysis-features.d.ts +3 -0
  122. package/dist/core/ingestion/frameworks/spring/analysis-features.js +7 -0
  123. package/dist/core/ingestion/frameworks/spring/bean-candidates.d.ts +30 -0
  124. package/dist/core/ingestion/frameworks/spring/bean-candidates.js +182 -0
  125. package/dist/core/ingestion/frameworks/spring/bean-catalog.d.ts +12 -0
  126. package/dist/core/ingestion/frameworks/spring/bean-catalog.js +26 -0
  127. package/dist/core/ingestion/frameworks/spring/config-bindings.d.ts +24 -0
  128. package/dist/core/ingestion/frameworks/spring/config-bindings.js +115 -0
  129. package/dist/core/ingestion/languages/c/captures.js +56 -0
  130. package/dist/core/ingestion/languages/c/query.js +17 -0
  131. package/dist/core/ingestion/languages/c/scope-resolver.js +6 -0
  132. package/dist/core/ingestion/languages/cobol/captures.js +93 -0
  133. package/dist/core/ingestion/languages/cobol/scope-resolver.js +7 -0
  134. package/dist/core/ingestion/languages/cpp/captures.js +365 -75
  135. package/dist/core/ingestion/languages/cpp/scope-resolver.js +14 -0
  136. package/dist/core/ingestion/languages/csharp/captures.js +25 -0
  137. package/dist/core/ingestion/languages/dart/captures.js +90 -2
  138. package/dist/core/ingestion/languages/dart/extension-type-preprocess.d.ts +7 -0
  139. package/dist/core/ingestion/languages/dart/extension-type-preprocess.js +30 -0
  140. package/dist/core/ingestion/languages/dart.js +2 -0
  141. package/dist/core/ingestion/languages/go/captures.js +34 -0
  142. package/dist/core/ingestion/languages/index.d.ts +1 -0
  143. package/dist/core/ingestion/languages/index.js +2 -0
  144. package/dist/core/ingestion/languages/java/analysis-features.d.ts +3 -0
  145. package/dist/core/ingestion/languages/java/analysis-features.js +13 -0
  146. package/dist/core/ingestion/languages/java/capture-side-channel.d.ts +22 -0
  147. package/dist/core/ingestion/languages/java/capture-side-channel.js +58 -0
  148. package/dist/core/ingestion/languages/java/captures.d.ts +4 -3
  149. package/dist/core/ingestion/languages/java/captures.js +193 -17
  150. package/dist/core/ingestion/languages/java/package-facts.d.ts +5 -0
  151. package/dist/core/ingestion/languages/java/package-facts.js +9 -0
  152. package/dist/core/ingestion/languages/java/package-siblings.d.ts +3 -16
  153. package/dist/core/ingestion/languages/java/package-siblings.js +8 -147
  154. package/dist/core/ingestion/languages/java/query.js +23 -0
  155. package/dist/core/ingestion/languages/java/scope-resolver.js +23 -0
  156. package/dist/core/ingestion/languages/java/spring-bean-metadata.d.ts +2 -0
  157. package/dist/core/ingestion/languages/java/spring-bean-metadata.js +8 -0
  158. package/dist/core/ingestion/languages/java/spring-config-bindings.d.ts +23 -0
  159. package/dist/core/ingestion/languages/java/spring-config-bindings.js +215 -0
  160. package/dist/core/ingestion/languages/java.js +3 -0
  161. package/dist/core/ingestion/languages/javascript/captures.js +16 -0
  162. package/dist/core/ingestion/languages/javascript/query.js +21 -0
  163. package/dist/core/ingestion/languages/jvm/package-facts.d.ts +35 -0
  164. package/dist/core/ingestion/languages/jvm/package-facts.js +40 -0
  165. package/dist/core/ingestion/languages/jvm/package-siblings.d.ts +14 -0
  166. package/dist/core/ingestion/languages/jvm/package-siblings.js +129 -0
  167. package/dist/core/ingestion/languages/kotlin/capture-side-channel.d.ts +17 -3
  168. package/dist/core/ingestion/languages/kotlin/capture-side-channel.js +42 -8
  169. package/dist/core/ingestion/languages/kotlin/captures.js +59 -0
  170. package/dist/core/ingestion/languages/kotlin/package-facts.d.ts +5 -0
  171. package/dist/core/ingestion/languages/kotlin/package-facts.js +9 -0
  172. package/dist/core/ingestion/languages/kotlin/package-siblings.d.ts +4 -0
  173. package/dist/core/ingestion/languages/kotlin/package-siblings.js +8 -0
  174. package/dist/core/ingestion/languages/kotlin/query.js +19 -0
  175. package/dist/core/ingestion/languages/kotlin/scope-resolver.js +9 -1
  176. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.d.ts +2 -0
  177. package/dist/core/ingestion/languages/kotlin/spring-bean-metadata.js +8 -0
  178. package/dist/core/ingestion/languages/kotlin.js +5 -6
  179. package/dist/core/ingestion/languages/move.d.ts +1 -0
  180. package/dist/core/ingestion/languages/move.js +27 -0
  181. package/dist/core/ingestion/languages/php/captures.js +40 -0
  182. package/dist/core/ingestion/languages/php/import-decomposer.js +12 -0
  183. package/dist/core/ingestion/languages/php/import-target.d.ts +2 -1
  184. package/dist/core/ingestion/languages/php/import-target.js +110 -2
  185. package/dist/core/ingestion/languages/php/interpret.js +10 -0
  186. package/dist/core/ingestion/languages/php/scope-resolver.js +1 -1
  187. package/dist/core/ingestion/languages/python/captures.d.ts +3 -4
  188. package/dist/core/ingestion/languages/python/captures.js +24 -5
  189. package/dist/core/ingestion/languages/python/interpret.js +4 -0
  190. package/dist/core/ingestion/languages/python/receiver-binding.d.ts +15 -2
  191. package/dist/core/ingestion/languages/python/receiver-binding.js +96 -2
  192. package/dist/core/ingestion/languages/python/simple-hooks.d.ts +5 -5
  193. package/dist/core/ingestion/languages/python/simple-hooks.js +15 -5
  194. package/dist/core/ingestion/languages/ruby/captures.js +42 -0
  195. package/dist/core/ingestion/languages/rust/captures.js +13 -0
  196. package/dist/core/ingestion/languages/rust/interpret.js +18 -0
  197. package/dist/core/ingestion/languages/rust/query.js +9 -0
  198. package/dist/core/ingestion/languages/rust/range-binding.js +6 -2
  199. package/dist/core/ingestion/languages/swift/captures.js +12 -0
  200. package/dist/core/ingestion/languages/typescript/captures.js +21 -0
  201. package/dist/core/ingestion/languages/typescript/nuxt-auto-imports.js +2 -1
  202. package/dist/core/ingestion/languages/typescript/query.js +37 -0
  203. package/dist/core/ingestion/markdown-processor.js +3 -2
  204. package/dist/core/ingestion/model/registration-table.js +1 -0
  205. package/dist/core/ingestion/parsing-processor.d.ts +3 -1
  206. package/dist/core/ingestion/parsing-processor.js +36 -1
  207. package/dist/core/ingestion/pipeline-phases/index.d.ts +2 -0
  208. package/dist/core/ingestion/pipeline-phases/index.js +2 -0
  209. package/dist/core/ingestion/pipeline-phases/parse-impl.js +56 -2
  210. package/dist/core/ingestion/pipeline-phases/parse.d.ts +0 -2
  211. package/dist/core/ingestion/pipeline-phases/parse.js +12 -3
  212. package/dist/core/ingestion/pipeline-phases/processes.d.ts +8 -0
  213. package/dist/core/ingestion/pipeline-phases/processes.js +11 -1
  214. package/dist/core/ingestion/pipeline-phases/spring-config.d.ts +37 -0
  215. package/dist/core/ingestion/pipeline-phases/spring-config.js +433 -0
  216. package/dist/core/ingestion/pipeline-phases/standalone-ingest.d.ts +10 -0
  217. package/dist/core/ingestion/pipeline-phases/standalone-ingest.js +6 -0
  218. package/dist/core/ingestion/pipeline.d.ts +4 -2
  219. package/dist/core/ingestion/pipeline.js +5 -2
  220. package/dist/core/ingestion/resolve-references.js +12 -0
  221. package/dist/core/ingestion/route-extractors/constant-resolver.d.ts +83 -0
  222. package/dist/core/ingestion/route-extractors/constant-resolver.js +131 -0
  223. package/dist/core/ingestion/route-extractors/python-const-resolver.d.ts +75 -0
  224. package/dist/core/ingestion/route-extractors/python-const-resolver.js +299 -0
  225. package/dist/core/ingestion/scope-extractor.js +306 -43
  226. package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +71 -2
  227. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.d.ts +7 -7
  228. package/dist/core/ingestion/scope-resolution/graph-bridge/callee-id-sink.js +8 -7
  229. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.d.ts +3 -1
  230. package/dist/core/ingestion/scope-resolution/graph-bridge/edges.js +6 -0
  231. package/dist/core/ingestion/scope-resolution/graph-bridge/ids.js +1 -0
  232. package/dist/core/ingestion/scope-resolution/graph-bridge/node-lookup.js +4 -1
  233. package/dist/core/ingestion/scope-resolution/graph-bridge/references-to-edges.js +7 -2
  234. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.d.ts +47 -0
  235. package/dist/core/ingestion/scope-resolution/passes/callable-value-flow.js +1138 -0
  236. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +16 -4
  237. package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +97 -1
  238. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.d.ts +60 -0
  239. package/dist/core/ingestion/scope-resolution/passes/property-dispatch.js +111 -0
  240. package/dist/core/ingestion/scope-resolution/passes/receiver-bound-calls.d.ts +4 -3
  241. package/dist/core/ingestion/scope-resolution/pipeline/phase.d.ts +5 -0
  242. package/dist/core/ingestion/scope-resolution/pipeline/phase.js +25 -38
  243. package/dist/core/ingestion/scope-resolution/pipeline/run.d.ts +6 -0
  244. package/dist/core/ingestion/scope-resolution/pipeline/run.js +147 -35
  245. package/dist/core/ingestion/scope-resolution/resolution-outcome.d.ts +1 -1
  246. package/dist/core/ingestion/scope-resolution/scope/walkers.js +73 -44
  247. package/dist/core/ingestion/taint/typescript-model.js +34 -2
  248. package/dist/core/ingestion/tree-sitter-queries.d.ts +2 -2
  249. package/dist/core/ingestion/tree-sitter-queries.js +23 -2
  250. package/dist/core/ingestion/type-extractors/jvm.js +17 -2
  251. package/dist/core/ingestion/utils/ast-helpers.d.ts +1 -0
  252. package/dist/core/ingestion/utils/ast-helpers.js +153 -2
  253. package/dist/core/ingestion/utils/callable-flow-captures.d.ts +94 -0
  254. package/dist/core/ingestion/utils/callable-flow-captures.js +878 -0
  255. package/dist/core/ingestion/utils/line-base.d.ts +20 -0
  256. package/dist/core/ingestion/utils/line-base.js +20 -0
  257. package/dist/core/ingestion/utils/symbol-labels.d.ts +21 -0
  258. package/dist/core/ingestion/utils/symbol-labels.js +45 -0
  259. package/dist/core/ingestion/workers/parse-worker.d.ts +34 -0
  260. package/dist/core/ingestion/workers/parse-worker.js +40 -5
  261. package/dist/core/ingestion/workers/result-merge.js +4 -0
  262. package/dist/core/ingestion/workers/worker-pool.d.ts +28 -0
  263. package/dist/core/ingestion/workers/worker-pool.js +128 -28
  264. package/dist/core/lbug/csv-generator.d.ts +15 -0
  265. package/dist/core/lbug/csv-generator.js +124 -27
  266. package/dist/core/lbug/cypher-escape.d.ts +20 -0
  267. package/dist/core/lbug/cypher-escape.js +20 -0
  268. package/dist/core/lbug/extension-load-error.d.ts +67 -0
  269. package/dist/core/lbug/extension-load-error.js +326 -0
  270. package/dist/core/lbug/extension-loader.d.ts +17 -2
  271. package/dist/core/lbug/extension-loader.js +38 -13
  272. package/dist/core/lbug/lbug-adapter.d.ts +203 -2
  273. package/dist/core/lbug/lbug-adapter.js +527 -86
  274. package/dist/core/lbug/lbug-config.d.ts +56 -2
  275. package/dist/core/lbug/lbug-config.js +267 -7
  276. package/dist/core/lbug/move-columns.d.ts +7 -0
  277. package/dist/core/lbug/move-columns.js +86 -0
  278. package/dist/core/lbug/native-check.d.ts +40 -0
  279. package/dist/core/lbug/native-check.js +90 -0
  280. package/dist/core/lbug/node-table-layout.d.ts +29 -0
  281. package/dist/core/lbug/node-table-layout.js +119 -0
  282. package/dist/core/lbug/pool-adapter.d.ts +23 -1
  283. package/dist/core/lbug/pool-adapter.js +115 -8
  284. package/dist/core/lbug/schema.d.ts +4 -3
  285. package/dist/core/lbug/schema.js +16 -16
  286. package/dist/core/lbug/sidecar-recovery.d.ts +172 -0
  287. package/dist/core/lbug/sidecar-recovery.js +418 -16
  288. package/dist/core/lbug/wal-checkpoint-driver.js +3 -0
  289. package/dist/core/move/artifact-download.d.ts +19 -0
  290. package/dist/core/move/artifact-download.js +179 -0
  291. package/dist/core/move/compiler-facts.d.ts +120 -0
  292. package/dist/core/move/compiler-facts.js +9 -0
  293. package/dist/core/move/consistency.d.ts +28 -0
  294. package/dist/core/move/consistency.js +98 -0
  295. package/dist/core/move/constants.d.ts +98 -0
  296. package/dist/core/move/constants.js +136 -0
  297. package/dist/core/move/discovery.d.ts +10 -0
  298. package/dist/core/move/discovery.js +22 -0
  299. package/dist/core/move/entry-points.d.ts +14 -0
  300. package/dist/core/move/entry-points.js +40 -0
  301. package/dist/core/move/facts-mapper.d.ts +75 -0
  302. package/dist/core/move/facts-mapper.js +534 -0
  303. package/dist/core/move/install-lock.d.ts +14 -0
  304. package/dist/core/move/install-lock.js +102 -0
  305. package/dist/core/move/install.d.ts +39 -0
  306. package/dist/core/move/install.js +391 -0
  307. package/dist/core/move/mcp-client.d.ts +115 -0
  308. package/dist/core/move/mcp-client.js +436 -0
  309. package/dist/core/move/move-ingest.d.ts +49 -0
  310. package/dist/core/move/move-ingest.js +320 -0
  311. package/dist/core/move/provision.d.ts +19 -0
  312. package/dist/core/move/provision.js +91 -0
  313. package/dist/core/move/release.d.ts +6 -0
  314. package/dist/core/move/release.js +10 -0
  315. package/dist/core/move/symbol-id.d.ts +35 -0
  316. package/dist/core/move/symbol-id.js +65 -0
  317. package/dist/core/move/type-parser.d.ts +11 -0
  318. package/dist/core/move/type-parser.js +38 -0
  319. package/dist/core/platform/capabilities.d.ts +0 -1
  320. package/dist/core/platform/capabilities.js +39 -8
  321. package/dist/core/run-analyze.d.ts +3 -3
  322. package/dist/core/run-analyze.js +1001 -184
  323. package/dist/core/search/fts-indexes.d.ts +31 -0
  324. package/dist/core/search/fts-indexes.js +73 -0
  325. package/dist/core/search/fts-schema.js +2 -0
  326. package/dist/core/tree-sitter/safe-parse.d.ts +8 -3
  327. package/dist/core/tree-sitter/safe-parse.js +21 -7
  328. package/dist/core/wiki/graph-queries.js +6 -5
  329. package/dist/core/wiki/llm-client.d.ts +8 -2
  330. package/dist/core/wiki/llm-client.js +41 -5
  331. package/dist/mcp/core/embedder.js +16 -2
  332. package/dist/mcp/http-transport.d.ts +5 -0
  333. package/dist/mcp/http-transport.js +19 -5
  334. package/dist/mcp/local/bean-metadata.d.ts +2 -0
  335. package/dist/mcp/local/bean-metadata.js +25 -0
  336. package/dist/mcp/local/line-display.d.ts +22 -0
  337. package/dist/mcp/local/line-display.js +3 -0
  338. package/dist/mcp/local/local-backend.d.ts +19 -1
  339. package/dist/mcp/local/local-backend.js +402 -155
  340. package/dist/mcp/local/pdg-impact.d.ts +5 -3
  341. package/dist/mcp/local/pdg-impact.js +5 -2
  342. package/dist/mcp/output-budget.d.ts +5 -0
  343. package/dist/mcp/output-budget.js +52 -0
  344. package/dist/mcp/read-only-policy.d.ts +12 -0
  345. package/dist/mcp/read-only-policy.js +102 -0
  346. package/dist/mcp/repository-policy.d.ts +34 -0
  347. package/dist/mcp/repository-policy.js +328 -0
  348. package/dist/mcp/resources.js +32 -5
  349. package/dist/mcp/server.d.ts +5 -2
  350. package/dist/mcp/server.js +29 -9
  351. package/dist/mcp/tools.d.ts +0 -8
  352. package/dist/mcp/tools.js +102 -5
  353. package/dist/server/analyze-job.d.ts +3 -0
  354. package/dist/server/analyze-job.js +17 -0
  355. package/dist/server/analyze-launch.d.ts +6 -0
  356. package/dist/server/analyze-launch.js +82 -6
  357. package/dist/server/analyze-worker-core.d.ts +2 -1
  358. package/dist/server/analyze-worker-core.js +5 -2
  359. package/dist/server/analyze-worker.js +29 -6
  360. package/dist/server/api.d.ts +30 -0
  361. package/dist/server/api.js +120 -34
  362. package/dist/server/mcp-http.d.ts +1 -1
  363. package/dist/server/mcp-http.js +4 -2
  364. package/dist/server/upload-ingest.js +2 -1
  365. package/dist/server/validation.js +2 -1
  366. package/dist/storage/git.d.ts +31 -0
  367. package/dist/storage/git.js +111 -1
  368. package/dist/storage/parse-cache.js +7 -1
  369. package/dist/storage/parsedfile-store.d.ts +8 -0
  370. package/dist/storage/parsedfile-store.js +165 -1
  371. package/dist/storage/repo-manager.d.ts +194 -2
  372. package/dist/storage/repo-manager.js +56 -1
  373. package/hooks/antigravity/gitnexus-antigravity-hook.cjs +50 -3
  374. package/hooks/claude/gitnexus-hook.cjs +59 -9
  375. package/hooks/claude/pre-tool-use.sh +0 -0
  376. package/hooks/claude/session-start.sh +0 -0
  377. package/package.json +21 -15
  378. package/scripts/cross-platform-tests.ts +56 -0
  379. package/scripts/ensure-fts.ts +43 -0
  380. package/scripts/install-duckdb-extension.mjs +85 -24
  381. package/scripts/run-cross-platform.ts +61 -6
  382. package/scripts/shard-arg.ts +30 -0
  383. package/scripts/sync-plugin-manifests.mjs +192 -0
  384. package/skills/gitnexus-lfg/README.md +55 -0
  385. package/skills/gitnexus-lfg/SKILL.md +86 -0
  386. package/skills/gitnexus-plan/README.md +142 -0
  387. package/skills/gitnexus-plan/SKILL.md +348 -0
  388. package/skills/gitnexus-plan/references/context-ledger.md +137 -0
  389. package/skills/gitnexus-plan/references/context-pack.md +126 -0
  390. package/skills/gitnexus-plan/references/evidence-provenance.md +272 -0
  391. package/skills/gitnexus-plan/references/pdg-slice.md +109 -0
  392. package/skills/gitnexus-plan/references/plan-template.md +201 -0
  393. package/skills/gitnexus-plan/scripts/evidence-provenance.mjs +2084 -0
  394. package/skills/gitnexus-review/SKILL.md +273 -0
  395. package/skills/gitnexus-review/ci-personas/ci-adversarial-lens.md +42 -0
  396. package/skills/gitnexus-review/ci-personas/ci-blast-radius-lens.md +39 -0
  397. package/skills/gitnexus-review/ci-personas/ci-correctness-lens.md +37 -0
  398. package/skills/gitnexus-review/ci-personas/ci-coverage-lens.md +40 -0
  399. package/skills/gitnexus-review/ci-personas/ci-critic-lens.md +42 -0
  400. package/skills/gitnexus-review/ci-personas/ci-security-lens.md +39 -0
  401. package/skills/gitnexus-work/README.md +71 -0
  402. package/skills/gitnexus-work/SKILL.md +269 -0
  403. package/skills/gitnexus-work/references/evidence-provenance.md +272 -0
  404. package/skills/gitnexus-work/scripts/evidence-provenance.mjs +2084 -0
  405. package/web/assets/ProcessFlowModal-B_bfBySy.js +22 -0
  406. package/web/assets/__vite-browser-external-bMKyYQkO.js +1 -0
  407. package/web/assets/agent-Bqxn-abU.js +626 -0
  408. package/web/assets/architecture-7EHR7CIX-6QZW5X65-BVWFvYz2.js +1 -0
  409. package/web/assets/architectureDiagram-UL44E2DR-CmG3uPWf.js +36 -0
  410. package/web/assets/{blockDiagram-7IZFK4PR-BkWhpzWB.js → blockDiagram-7IZFK4PR-DBefcjof.js} +7 -7
  411. package/web/assets/{c4Diagram-Y2BXMSZH-DtBvpzWD.js → c4Diagram-Y2BXMSZH-EjWnjEJl.js} +6 -6
  412. package/web/assets/chunk-2T2R6R2M-Bb6Sy3_j.js +4 -0
  413. package/web/assets/chunk-2UTLFMKG-CXlhF3Pt.js +1 -0
  414. package/web/assets/chunk-3SSMPTDK-rPsRM1x0.js +321 -0
  415. package/web/assets/chunk-4R4BOZG6-Be_F0JoX.js +159 -0
  416. package/web/assets/{chunk-6764PJDD-DpIS7hxD.js → chunk-6764PJDD-C7xxk063.js} +1 -1
  417. package/web/assets/chunk-67TQ5CYL-CA7OhIEf.js +124 -0
  418. package/web/assets/chunk-7FYTHRHK-CsmYIswB.js +32 -0
  419. package/web/assets/chunk-7J6CGLKN-BlKwgXKs.js +10 -0
  420. package/web/assets/chunk-7W6UQGC5-pyKGssV3.js +1 -0
  421. package/web/assets/chunk-C62D2QBJ-3gdL8EKc.js +1 -0
  422. package/web/assets/chunk-CEXFNPSA-CjwtMDkc.js +1 -0
  423. package/web/assets/{chunk-INKRHTLW-Nu4ri9P-.js → chunk-INKRHTLW-Ckl3_KkO.js} +13 -13
  424. package/web/assets/chunk-J5EP6P6S-L19oz55R.js +1 -0
  425. package/web/assets/{chunk-KGFNY3KK-JGMJvKCK.js → chunk-KGFNY3KK-BZeP-55u.js} +17 -17
  426. package/web/assets/chunk-KGYTTC2M-zm6n242I.js +1 -0
  427. package/web/assets/{chunk-KRXBNO2N-BW5o0KUN.js → chunk-KRXBNO2N-C-UNuKKf.js} +1 -1
  428. package/web/assets/{chunk-LCXTWHL2-CfLLCywY.js → chunk-LCXTWHL2-C162wE5z.js} +5 -5
  429. package/web/assets/chunk-LII3EMHJ-BL6lKJ_P.js +1 -0
  430. package/web/assets/chunk-LRIF4GLE-n59lhprL.js +1 -0
  431. package/web/assets/chunk-QA3QBVWF-DVXPOIxe.js +2 -0
  432. package/web/assets/chunk-RERM46MO-B5dAdWpP.js +1 -0
  433. package/web/assets/chunk-RG4AUYOV-ZNgyLFq6.js +206 -0
  434. package/web/assets/chunk-RKZBBQEN-MyIQbGgD.js +1 -0
  435. package/web/assets/chunk-RLI5ZMPA-CkXZ0y0U.js +1 -0
  436. package/web/assets/chunk-T2UQINTJ-BEyXhZWe.js +1 -0
  437. package/web/assets/chunk-UP6H54XL-BG-n7qDp.js +1 -0
  438. package/web/assets/chunk-UXSXWOXI-CW1_r5cS.js +1 -0
  439. package/web/assets/chunk-UY5QBCOK-ByqTVLvh.js +1 -0
  440. package/web/assets/chunk-VU6ZFW4Y-BLeasdkU.js +2 -0
  441. package/web/assets/{chunk-W44A43WB-JqMLIpR0.js → chunk-W44A43WB-BN8EQc_u.js} +1 -1
  442. package/web/assets/chunk-ZXARS5L4-C3v-4Fsw.js +1 -0
  443. package/web/assets/classDiagram-KGZ6W3CR-olpO3fMe.js +1 -0
  444. package/web/assets/classDiagram-v2-72OJOZXJ-olpO3fMe.js +1 -0
  445. package/web/assets/cose-bilkent-UX7MHV2Q-BmnZ7Mvj.js +1 -0
  446. package/web/assets/dagre-ND4H6XIP-CY4iIF7v.js +4 -0
  447. package/web/assets/diagram-3NCE3AQN-CO6QpzEE.js +43 -0
  448. package/web/assets/diagram-GF46GFSD-B2atbzmU.js +24 -0
  449. package/web/assets/diagram-HNR7UZ2L-DVRltWbL.js +3 -0
  450. package/web/assets/diagram-QXG6HAR7-DR6AHD2h.js +24 -0
  451. package/web/assets/diagram-WEQXMOUZ-DkpoMwTL.js +10 -0
  452. package/web/assets/erDiagram-L5TCEMPS-n8g_90bc.js +85 -0
  453. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-CgFBM7e-.js +1 -0
  454. package/web/assets/flowDiagram-H6V6AXG4-SGMDiCkB.js +162 -0
  455. package/web/assets/ganttDiagram-JCBTUEKG-Cb3UBqRS.js +292 -0
  456. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-DCJv7SII.js +1 -0
  457. package/web/assets/gitGraphDiagram-S2ZK5IYY-Bs9CR7tq.js +106 -0
  458. package/web/assets/index-CX_fADmQ.css +2 -0
  459. package/web/assets/index-D1Z3dGGz.js +575 -0
  460. package/web/assets/info-J43DQDTF-KCYPFFUO-BfNy-9Nd.js +1 -0
  461. package/web/assets/infoDiagram-3YFTVSEB-T368on4D.js +2 -0
  462. package/web/assets/{ishikawaDiagram-BNXS4ZKH-DfYpxnE5.js → ishikawaDiagram-BNXS4ZKH-XpjJRU9h.js} +6 -6
  463. package/web/assets/journeyDiagram-M6C3CM3L-C6wjooas.js +139 -0
  464. package/web/assets/kanban-definition-75IXJCU3-5_UVY79g.js +89 -0
  465. package/web/assets/{katex-K3KEBU37-CTc5BslQ.js → katex-K3KEBU37-qRQBy-EZ.js} +2 -2
  466. package/web/assets/{mindmap-definition-2TDM6QVE-DypvbOMQ.js → mindmap-definition-2TDM6QVE-8xDLzk2e.js} +29 -29
  467. package/web/assets/node-Ct_zna8U.js +8 -0
  468. package/web/assets/packet-YPE3B663-LP52Z2RK-D4qkeG9k.js +1 -0
  469. package/web/assets/pie-LRSECV5Y-TCRJHUBD-B_yMKyQa.js +1 -0
  470. package/web/assets/pieDiagram-CU6KROY3-Bv4LpAbr.js +30 -0
  471. package/web/assets/preload-helper-Czpn1I53.js +1 -0
  472. package/web/assets/{quadrantDiagram-VICAPDV7-yXSZ2lLz.js → quadrantDiagram-VICAPDV7-DR54jOeR.js} +6 -6
  473. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DeD6yN_0.js +1 -0
  474. package/web/assets/requirementDiagram-JXO7QTGE-PEkg7sKC.js +84 -0
  475. package/web/assets/rolldown-runtime-QTnfLwEv.js +1 -0
  476. package/web/assets/sankeyDiagram-URQDO5SZ-DDWEtjcs.js +40 -0
  477. package/web/assets/sdk-CzHHH8tD.js +37 -0
  478. package/web/assets/sequenceDiagram-VS2MUI6T-Bv-uwANx.js +162 -0
  479. package/web/assets/src-JV30wyV8.js +1 -0
  480. package/web/assets/stateDiagram-7D4R322I-DVNjmkEq.js +1 -0
  481. package/web/assets/stateDiagram-v2-36443NZ5-CyN4Fh7_.js +1 -0
  482. package/web/assets/timeline-definition-O6YCAMPW-Qmsuo7qS.js +120 -0
  483. package/web/assets/treeView-BLDUP644-QA4HXRO3-CDuSYnd4.js +1 -0
  484. package/web/assets/treemap-LRROVOQU-LLAWBHMP-imazucyJ.js +1 -0
  485. package/web/assets/vennDiagram-MWXL3ELB-BD1iK1SX.js +34 -0
  486. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-DqrT9tB8.js +1 -0
  487. package/web/assets/wardleyDiagram-CUQ6CDDI-D6TzLVob.js +78 -0
  488. package/web/assets/{xychartDiagram-N2JHSOCM-BOLm0eNm.js → xychartDiagram-N2JHSOCM-CoZ_Tits.js} +6 -6
  489. package/web/index.html +18 -10
  490. package/skills/gitnexus-pr-review.md +0 -163
  491. package/web/assets/agent-Dli_x7bU.js +0 -660
  492. package/web/assets/architecture-7EHR7CIX-6QZW5X65-DxJw65fT.js +0 -1
  493. package/web/assets/architectureDiagram-UL44E2DR-dEkqUZN9.js +0 -36
  494. package/web/assets/chunk-3SSMPTDK-B4_etUhr.js +0 -321
  495. package/web/assets/chunk-67TQ5CYL-4sNPJU1q.js +0 -124
  496. package/web/assets/chunk-7W6UQGC5-KyEG0HQg.js +0 -1
  497. package/web/assets/chunk-KGYTTC2M-CWC_c3H9.js +0 -161
  498. package/web/assets/chunk-LII3EMHJ-D-jm-dLa.js +0 -1
  499. package/web/assets/chunk-QA3QBVWF-BgRW3SXd.js +0 -2
  500. package/web/assets/chunk-RG4AUYOV-CqWzWsV3.js +0 -206
  501. package/web/assets/chunk-T2UQINTJ-DSBqkzH7.js +0 -1
  502. package/web/assets/chunk-UY5QBCOK-DyF0vyGd.js +0 -1
  503. package/web/assets/chunk-ZXARS5L4-CxN8oiwI.js +0 -1
  504. package/web/assets/classDiagram-KGZ6W3CR-CMne4tG9.js +0 -1
  505. package/web/assets/classDiagram-v2-72OJOZXJ-CMne4tG9.js +0 -1
  506. package/web/assets/cose-bilkent-UX7MHV2Q-D71wNYRJ.js +0 -1
  507. package/web/assets/dagre-ND4H6XIP-Co5rRx9X.js +0 -4
  508. package/web/assets/diagram-3NCE3AQN-DBp4O00j.js +0 -43
  509. package/web/assets/diagram-GF46GFSD-6N_8yS0i.js +0 -24
  510. package/web/assets/diagram-HNR7UZ2L-DFCfd5LI.js +0 -3
  511. package/web/assets/diagram-QXG6HAR7-Di093rFg.js +0 -24
  512. package/web/assets/diagram-WEQXMOUZ-DZWi4SUN.js +0 -10
  513. package/web/assets/erDiagram-L5TCEMPS-8X1y6R4Y.js +0 -85
  514. package/web/assets/eventmodeling-FCH6USID-MREXMVOE-BQm9QzEa.js +0 -1
  515. package/web/assets/flowDiagram-H6V6AXG4-CMpY8Ufn.js +0 -162
  516. package/web/assets/ganttDiagram-JCBTUEKG-D3iL2Aet.js +0 -292
  517. package/web/assets/gitGraph-WXDBUCRP-R675I2BI-Cr_Bm2Nb.js +0 -1
  518. package/web/assets/gitGraphDiagram-S2ZK5IYY-CPIDgxGm.js +0 -106
  519. package/web/assets/index-KctnI3Vq.js +0 -635
  520. package/web/assets/index-_lgn7hs5.css +0 -2
  521. package/web/assets/info-J43DQDTF-KCYPFFUO-Cs4p2oyk.js +0 -1
  522. package/web/assets/infoDiagram-3YFTVSEB-BaLMZkUg.js +0 -2
  523. package/web/assets/journeyDiagram-M6C3CM3L-CvArszLo.js +0 -139
  524. package/web/assets/kanban-definition-75IXJCU3-CpfVLLf9.js +0 -89
  525. package/web/assets/packet-YPE3B663-LP52Z2RK-CKCrztD2.js +0 -1
  526. package/web/assets/pie-LRSECV5Y-TCRJHUBD-BB7pHqoD.js +0 -1
  527. package/web/assets/pieDiagram-CU6KROY3-s27EFWgP.js +0 -30
  528. package/web/assets/radar-GUYGQ44K-RDLRG3WG-DhoTOcuK.js +0 -1
  529. package/web/assets/requirementDiagram-JXO7QTGE-CWhqInuf.js +0 -84
  530. package/web/assets/sankeyDiagram-URQDO5SZ-1qEjlFIB.js +0 -40
  531. package/web/assets/sequenceDiagram-VS2MUI6T-RyTlZ5cR.js +0 -162
  532. package/web/assets/stateDiagram-7D4R322I-DTjVfX4A.js +0 -1
  533. package/web/assets/stateDiagram-v2-36443NZ5-xY9_k9_Q.js +0 -1
  534. package/web/assets/timeline-definition-O6YCAMPW-DrrqLYAf.js +0 -120
  535. package/web/assets/treeView-BLDUP644-QA4HXRO3-ODehyGKL.js +0 -1
  536. package/web/assets/treemap-LRROVOQU-LLAWBHMP-BfpgC-7o.js +0 -1
  537. package/web/assets/vennDiagram-MWXL3ELB-B0RkWAim.js +0 -34
  538. package/web/assets/wardley-L42UT6IY-5TKZOOLJ-CNeL6VHE.js +0 -1
  539. package/web/assets/wardleyDiagram-CUQ6CDDI-boUxiQ5F.js +0 -78
@@ -34,8 +34,10 @@ export declare function splitCalleeIds(raw: unknown): string[];
34
34
  * Contract version of the mode:'pdg' impact result shape. A stable discriminator
35
35
  * for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
36
36
  * Bump on any breaking change to the PDG result fields.
37
+ * v2: `startLine` in the result is now 1-based display (#2380), matching the
38
+ * context/query/impact tools (was 0-based).
37
39
  */
38
- export declare const PDG_RESULT_VERSION: 1;
40
+ export declare const PDG_RESULT_VERSION: 2;
39
41
  /** A reachable dependence block resolved to its source statement. */
40
42
  export interface PdgStatement {
41
43
  /** 1-based source line where the statement's block starts. */
@@ -105,7 +107,7 @@ export interface PdgInterproceduralImpact {
105
107
  export interface PdgImpactBaseResult extends PdgImpactParityFields {
106
108
  mode: 'pdg';
107
109
  /** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
108
- pdgResultVersion: 1;
110
+ pdgResultVersion: 2;
109
111
  target: PdgImpactTarget;
110
112
  direction: 'upstream' | 'downstream';
111
113
  impactedCount: number;
@@ -172,7 +174,7 @@ export interface PdgImpactDegradedResult extends PdgImpactBaseResult {
172
174
  export interface PdgImpactErrorResult {
173
175
  mode?: 'pdg';
174
176
  /** Contract version of the mode:'pdg' impact result shape; bump on any breaking change to the PDG result fields. */
175
- pdgResultVersion: 1;
177
+ pdgResultVersion: 2;
176
178
  error: string;
177
179
  target: PdgImpactTarget;
178
180
  direction: 'upstream' | 'downstream';
@@ -9,6 +9,7 @@ import path from 'path';
9
9
  import { loadMeta } from '../../storage/repo-manager.js';
10
10
  import { IMPACT_MAX_DEPTH, PDG_QUERY_DEFAULT_LIMIT, PDG_QUERY_MAX_LIMIT } from '../tools.js';
11
11
  import { CALLEES_TRUNCATED_SENTINEL, CALLEE_ID_SEP } from '../../core/ingestion/cfg/emit.js';
12
+ import { toDisplayLine } from './line-display.js';
12
13
  import { decodeCallSummary } from '../../core/ingestion/taint/call-summary-codec.js';
13
14
  import { decodeReachingDefReason } from '../../core/ingestion/cfg/reaching-def-reason-codec.js';
14
15
  import { getProviderForFile } from '../../core/ingestion/languages/index.js';
@@ -84,8 +85,10 @@ export function splitCalleeIds(raw) {
84
85
  * Contract version of the mode:'pdg' impact result shape. A stable discriminator
85
86
  * for external MCP/agent consumers — distinct from the DB INCREMENTAL_SCHEMA_VERSION.
86
87
  * Bump on any breaking change to the PDG result fields.
88
+ * v2: `startLine` in the result is now 1-based display (#2380), matching the
89
+ * context/query/impact tools (was 0-based).
87
90
  */
88
- export const PDG_RESULT_VERSION = 1;
91
+ export const PDG_RESULT_VERSION = 2;
89
92
  /**
90
93
  * FU-B-2 intra-block def→use line walk. Given a block's self REACHING_DEF
91
94
  * def→use line PAIRS (every `defLine → useLine` step decoded from the edge
@@ -519,7 +522,7 @@ function assemblePdgImpactResult(input) {
519
522
  name: s.name,
520
523
  type: s.type,
521
524
  filePath: s.filePath,
522
- ...(s.startLine !== undefined ? { startLine: s.startLine } : {}),
525
+ ...(s.startLine !== undefined ? { startLine: toDisplayLine(s.startLine) } : {}),
523
526
  ...(s.ambiguous ? { ambiguous: true } : {}),
524
527
  ...(s.id === null ? { unresolved: true } : {}),
525
528
  pdgEvidence: (s.id === null ? 'degraded' : 'owner-projection'),
@@ -0,0 +1,5 @@
1
+ export declare const MCP_TOKEN_ESTIMATE_BYTES = 4;
2
+ export declare const MCP_TRUNCATION_MARKER = "\n\u2026";
3
+ export declare function resolveMcpMaxTokens(toolName: string, args: Record<string, unknown> | undefined, env?: NodeJS.ProcessEnv): number | undefined;
4
+ export declare function applyMcpMaxTokens(text: string, maxTokens: number | undefined): string;
5
+ export declare function withoutMcpBudgetArg(args: Record<string, unknown> | undefined): Record<string, unknown> | undefined;
@@ -0,0 +1,52 @@
1
+ const BUDGETED_TOOLS = new Set(['query', 'context', 'impact']);
2
+ export const MCP_TOKEN_ESTIMATE_BYTES = 4;
3
+ export const MCP_TRUNCATION_MARKER = '\n…';
4
+ function parsePositiveInteger(value, source) {
5
+ if (typeof value === 'number' && Number.isSafeInteger(value) && value > 0)
6
+ return value;
7
+ if (typeof value === 'string' && /^[1-9]\d*$/.test(value.trim())) {
8
+ const parsed = Number(value.trim());
9
+ if (Number.isSafeInteger(parsed))
10
+ return parsed;
11
+ }
12
+ throw new Error(`${source} must be a positive integer.`);
13
+ }
14
+ export function resolveMcpMaxTokens(toolName, args, env = process.env) {
15
+ if (!BUDGETED_TOOLS.has(toolName))
16
+ return undefined;
17
+ if (args?.maxTokens !== undefined)
18
+ return parsePositiveInteger(args.maxTokens, 'maxTokens');
19
+ const configured = env.GITNEXUS_MCP_DEFAULT_MAX_TOKENS;
20
+ if (configured === undefined || configured.trim() === '')
21
+ return undefined;
22
+ return parsePositiveInteger(configured, 'GITNEXUS_MCP_DEFAULT_MAX_TOKENS');
23
+ }
24
+ function utf8Prefix(text, maxBytes) {
25
+ let bytes = 0;
26
+ const codePoints = [];
27
+ for (const codePoint of text) {
28
+ const codePointBytes = Buffer.byteLength(codePoint, 'utf8');
29
+ if (bytes + codePointBytes > maxBytes)
30
+ break;
31
+ codePoints.push(codePoint);
32
+ bytes += codePointBytes;
33
+ }
34
+ return codePoints.join('');
35
+ }
36
+ export function applyMcpMaxTokens(text, maxTokens) {
37
+ if (maxTokens === undefined)
38
+ return text;
39
+ const textBytes = Buffer.byteLength(text, 'utf8');
40
+ if (maxTokens >= Math.ceil(textBytes / MCP_TOKEN_ESTIMATE_BYTES))
41
+ return text;
42
+ const maxBytes = maxTokens * MCP_TOKEN_ESTIMATE_BYTES;
43
+ const markerBytes = Buffer.byteLength(MCP_TRUNCATION_MARKER, 'utf8');
44
+ return utf8Prefix(text, Math.max(0, maxBytes - markerBytes)) + MCP_TRUNCATION_MARKER;
45
+ }
46
+ export function withoutMcpBudgetArg(args) {
47
+ if (!args || !Object.prototype.hasOwnProperty.call(args, 'maxTokens'))
48
+ return args;
49
+ const backendArgs = { ...args };
50
+ delete backendArgs.maxTokens;
51
+ return backendArgs;
52
+ }
@@ -0,0 +1,12 @@
1
+ import type { GITNEXUS_TOOLS } from './tools.js';
2
+ type GitNexusTool = (typeof GITNEXUS_TOOLS)[number];
3
+ export declare const MCP_READ_ONLY_TOOLS: Set<string>;
4
+ export declare function resolveMcpReadOnlyMode(env?: NodeJS.ProcessEnv): boolean;
5
+ export declare function assertMcpReadOnlyToolCall(toolName: string, args: Record<string, unknown> | undefined, readOnly: boolean): void;
6
+ export declare function readOnlyResourceTemplateAllowed(uriTemplate: string, readOnly: boolean): boolean;
7
+ export declare function assertMcpReadOnlyResource(uri: string, readOnly: boolean): void;
8
+ export declare function filterMcpReadOnlyResourceContent(content: string, readOnly: boolean): string;
9
+ /** Shared with repository-policy.ts so both policies scrub identically. */
10
+ export declare function scrubGroupDescription(description: string): string;
11
+ export declare function toolForReadOnlyMcp(tool: GitNexusTool, readOnly: boolean): GitNexusTool;
12
+ export {};
@@ -0,0 +1,102 @@
1
+ export const MCP_READ_ONLY_TOOLS = new Set([
2
+ 'list_repos',
3
+ 'query',
4
+ 'context',
5
+ 'detect_changes',
6
+ 'check',
7
+ 'impact',
8
+ 'explain',
9
+ 'pdg_query',
10
+ 'route_map',
11
+ 'tool_map',
12
+ 'shape_check',
13
+ 'api_impact',
14
+ 'trace',
15
+ ]);
16
+ const MCP_READ_ONLY_ALIASES = new Set(['search', 'explore', 'overview']);
17
+ export function resolveMcpReadOnlyMode(env = process.env) {
18
+ const value = env.GITNEXUS_MCP_READ_ONLY?.trim();
19
+ if (value === undefined || value === '' || value === '0')
20
+ return false;
21
+ if (value === '1')
22
+ return true;
23
+ throw new Error('GITNEXUS_MCP_READ_ONLY must be 0 or 1.');
24
+ }
25
+ export function assertMcpReadOnlyToolCall(toolName, args, readOnly) {
26
+ if (!readOnly)
27
+ return;
28
+ if (!MCP_READ_ONLY_TOOLS.has(toolName) && !MCP_READ_ONLY_ALIASES.has(toolName)) {
29
+ throw new Error(`Tool "${toolName}" is not available in GitNexus MCP read-only mode.`);
30
+ }
31
+ if (typeof args?.repo === 'string' && args.repo.trim().startsWith('@')) {
32
+ throw new Error('Group routing is not available in GitNexus MCP read-only mode.');
33
+ }
34
+ // crossDepth/subgroup only do anything on the @group path rejected above,
35
+ // but rejecting them here keeps the advertised schema and the dispatch
36
+ // contract in agreement.
37
+ for (const groupOnlyArg of ['crossDepth', 'subgroup']) {
38
+ if (args?.[groupOnlyArg] !== undefined) {
39
+ throw new Error(`Parameter "${groupOnlyArg}" is not available in GitNexus MCP read-only mode.`);
40
+ }
41
+ }
42
+ }
43
+ export function readOnlyResourceTemplateAllowed(uriTemplate, readOnly) {
44
+ return !readOnly || !/^gitnexus:\/\/group\//iu.test(uriTemplate);
45
+ }
46
+ export function assertMcpReadOnlyResource(uri, readOnly) {
47
+ if (!readOnly)
48
+ return;
49
+ let isGroupResource = false;
50
+ try {
51
+ const parsed = new URL(uri);
52
+ isGroupResource =
53
+ parsed.protocol.toLowerCase() === 'gitnexus:' && parsed.hostname.toLowerCase() === 'group';
54
+ }
55
+ catch {
56
+ // Invalid resource URIs are rejected by the normal parser. This fallback
57
+ // keeps obviously group-shaped malformed inputs fail-closed as well.
58
+ isGroupResource = /^gitnexus:\/\/group(?:\/|$)/iu.test(uri);
59
+ }
60
+ if (isGroupResource) {
61
+ throw new Error('Group resources are not available in GitNexus MCP read-only mode.');
62
+ }
63
+ }
64
+ // Cosmetic only: dispatch enforcement above is the actual boundary. If the
65
+ // generated resource format drifts and a hidden route slips through here, the
66
+ // caller still gets a clean rejection at dispatch.
67
+ export function filterMcpReadOnlyResourceContent(content, readOnly) {
68
+ if (!readOnly)
69
+ return content;
70
+ return content
71
+ .split('\n')
72
+ .filter((line) => !/^\s*-\s+(?:rename|cypher|group_sync|group_list):/u.test(line) &&
73
+ !/^\|\s*`(?:rename|cypher|group_sync|group_list)`\s*\|/u.test(line) &&
74
+ !line.includes('gitnexus://group/'))
75
+ .join('\n');
76
+ }
77
+ /** Shared with repository-policy.ts so both policies scrub identically. */
78
+ export function scrubGroupDescription(description) {
79
+ return description
80
+ .replace(/\nGROUP MODE:[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '')
81
+ .replace(/\nCROSS-REPO \(experimental\):[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '')
82
+ .replace(/\nDESTINATION TRACE \(cross-repo\):[\s\S]*?(?=\n\n[A-Z][A-Z ()-]*:|$)/gu, '');
83
+ }
84
+ export function toolForReadOnlyMcp(tool, readOnly) {
85
+ if (!readOnly)
86
+ return tool;
87
+ const properties = { ...tool.inputSchema.properties };
88
+ const repo = properties.repo;
89
+ if (repo && typeof repo === 'object') {
90
+ properties.repo = {
91
+ ...repo,
92
+ description: 'Indexed repository name or path. Group-mode values beginning with @ are unavailable in MCP read-only mode.',
93
+ };
94
+ }
95
+ delete properties.subgroup;
96
+ delete properties.crossDepth;
97
+ return {
98
+ ...tool,
99
+ description: `${scrubGroupDescription(tool.description)}\n\nGitNexus MCP read-only mode excludes raw Cypher, mutation, and group routing.`,
100
+ inputSchema: { ...tool.inputSchema, properties },
101
+ };
102
+ }
@@ -0,0 +1,34 @@
1
+ import type { LocalBackend } from './local/local-backend.js';
2
+ import type { GITNEXUS_TOOLS } from './tools.js';
3
+ type GitNexusTool = (typeof GITNEXUS_TOOLS)[number];
4
+ interface ResolvedRepository {
5
+ name: string;
6
+ path: string;
7
+ pathKey: string;
8
+ }
9
+ export declare class McpRepositoryPolicy {
10
+ readonly restricted: boolean;
11
+ readonly configured: boolean;
12
+ private readonly registry;
13
+ private readonly allowed;
14
+ private readonly allowedPathKeys;
15
+ private readonly defaultRepo?;
16
+ private readonly uniqueAllowedContextNames;
17
+ static unrestricted(): McpRepositoryPolicy;
18
+ constructor(registry: readonly ResolvedRepository[], allowed: readonly ResolvedRepository[] | undefined, defaultRepo: ResolvedRepository | undefined);
19
+ private resolveRuntimeRepo;
20
+ private repoForArgs;
21
+ private normalizeToolArgs;
22
+ private listAllowedRepos;
23
+ private listReposPage;
24
+ private callTool;
25
+ private resolveRepo;
26
+ assertResourceUri(uri: string): void;
27
+ resourceTemplateAllowed(uriTemplate: string): boolean;
28
+ toolAllowed(toolName: string): boolean;
29
+ toolForMcp(tool: GitNexusTool): GitNexusTool;
30
+ scopeBackend(backend: LocalBackend): LocalBackend;
31
+ }
32
+ export declare function mcpRepositoryPolicyConfigured(env?: NodeJS.ProcessEnv): boolean;
33
+ export declare function createMcpRepositoryPolicy(backend: LocalBackend, env?: NodeJS.ProcessEnv): Promise<McpRepositoryPolicy>;
34
+ export {};
@@ -0,0 +1,328 @@
1
+ import path from 'node:path';
2
+ import { parseListReposPagination } from './local/local-backend.js';
3
+ import { scrubGroupDescription } from './read-only-policy.js';
4
+ import { LIST_REPOS_DEFAULT_LIMIT, LIST_REPOS_MAX_LIMIT } from './tools.js';
5
+ const CANONICAL_ALLOWED = 'GITNEXUS_MCP_ALLOWED_REPOS';
6
+ const CANONICAL_DEFAULT = 'GITNEXUS_MCP_DEFAULT_REPO';
7
+ function configuredValue(env, key) {
8
+ const value = env[key];
9
+ return value === undefined ? undefined : { key, value };
10
+ }
11
+ function parseRepositoryPolicy(env) {
12
+ const allowedRaw = configuredValue(env, CANONICAL_ALLOWED);
13
+ const defaultRaw = configuredValue(env, CANONICAL_DEFAULT);
14
+ let allowed;
15
+ if (allowedRaw) {
16
+ allowed = allowedRaw.value
17
+ .split(',')
18
+ .map((entry) => entry.trim())
19
+ .filter(Boolean);
20
+ if (allowed.length === 0)
21
+ throw new Error(`${allowedRaw.key} must not be blank.`);
22
+ }
23
+ let defaultRepo;
24
+ if (defaultRaw) {
25
+ defaultRepo = defaultRaw.value.trim();
26
+ if (!defaultRepo)
27
+ throw new Error(`${defaultRaw.key} must not be blank.`);
28
+ }
29
+ return { allowed, defaultRepo };
30
+ }
31
+ function normalizedPath(value) {
32
+ const resolved = path.resolve(value);
33
+ return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
34
+ }
35
+ function isAbsolutePath(value) {
36
+ return path.isAbsolute(value) || path.win32.isAbsolute(value);
37
+ }
38
+ function resolveSpecifier(specifier, registry) {
39
+ const trimmed = specifier.trim();
40
+ const matches = isAbsolutePath(trimmed)
41
+ ? registry.filter((repo) => repo.pathKey === normalizedPath(trimmed))
42
+ : registry.filter((repo) => repo.name.toLowerCase() === trimmed.toLowerCase());
43
+ if (matches.length === 0)
44
+ return { reason: 'invalid' };
45
+ if (matches.length > 1)
46
+ return { reason: 'ambiguous' };
47
+ return { repo: matches[0] };
48
+ }
49
+ function startupResolutionError(reason) {
50
+ return new Error(reason === 'ambiguous'
51
+ ? 'MCP repository configuration contains an ambiguous repository selection.'
52
+ : 'MCP repository configuration contains an invalid repository selection.');
53
+ }
54
+ function unavailableRepositoryError() {
55
+ return new Error('Repository is not available through this MCP server.');
56
+ }
57
+ export class McpRepositoryPolicy {
58
+ restricted;
59
+ configured;
60
+ registry;
61
+ allowed;
62
+ allowedPathKeys;
63
+ defaultRepo;
64
+ uniqueAllowedContextNames;
65
+ static unrestricted() {
66
+ return new McpRepositoryPolicy([], undefined, undefined);
67
+ }
68
+ constructor(registry, allowed, defaultRepo) {
69
+ this.registry = registry;
70
+ this.restricted = allowed !== undefined;
71
+ this.configured = this.restricted || defaultRepo !== undefined;
72
+ this.allowed = allowed ?? registry;
73
+ this.allowedPathKeys = new Set(this.allowed.map((repo) => repo.pathKey));
74
+ this.defaultRepo = defaultRepo;
75
+ const registryNameCounts = new Map();
76
+ for (const repo of registry) {
77
+ const name = repo.name.toLowerCase();
78
+ registryNameCounts.set(name, (registryNameCounts.get(name) ?? 0) + 1);
79
+ }
80
+ this.uniqueAllowedContextNames = new Set(this.allowed
81
+ .map((repo) => repo.name.toLowerCase())
82
+ .filter((name) => registryNameCounts.get(name) === 1));
83
+ }
84
+ resolveRuntimeRepo(specifier) {
85
+ const result = resolveSpecifier(specifier, this.registry);
86
+ if (!result.repo || (this.restricted && !this.allowedPathKeys.has(result.repo.pathKey))) {
87
+ throw unavailableRepositoryError();
88
+ }
89
+ return result.repo;
90
+ }
91
+ repoForArgs(args) {
92
+ const explicit = args?.repo;
93
+ if (explicit !== undefined) {
94
+ if (typeof explicit !== 'string')
95
+ throw unavailableRepositoryError();
96
+ if (explicit.trim().startsWith('@')) {
97
+ if (this.restricted) {
98
+ throw new Error('Group routing is unavailable when an MCP repository allowlist is set.');
99
+ }
100
+ return undefined;
101
+ }
102
+ return this.resolveRuntimeRepo(explicit);
103
+ }
104
+ if (this.defaultRepo)
105
+ return this.defaultRepo;
106
+ if (this.restricted && this.allowed.length === 1)
107
+ return this.allowed[0];
108
+ if (this.restricted && this.allowed.length > 1) {
109
+ throw new Error('Specify an explicit repo because multiple repositories are allowed.');
110
+ }
111
+ return undefined;
112
+ }
113
+ normalizeToolArgs(args) {
114
+ if (!this.configured)
115
+ return args;
116
+ if (!this.restricted && args?.repo !== undefined)
117
+ return args;
118
+ const selected = this.repoForArgs(args);
119
+ if (!selected)
120
+ return args;
121
+ return { ...(args ?? {}), repo: selected.path };
122
+ }
123
+ async listAllowedRepos(backend) {
124
+ const current = await backend.listRepos();
125
+ if (!this.restricted)
126
+ return current;
127
+ return current
128
+ .filter((repo) => this.allowedPathKeys.has(normalizedPath(repo.path)))
129
+ .map((repo) => {
130
+ const siblings = repo.siblings?.filter((sibling) => this.allowedPathKeys.has(normalizedPath(sibling.path)));
131
+ return {
132
+ ...repo,
133
+ siblings: siblings && siblings.length > 0 ? siblings : undefined,
134
+ };
135
+ });
136
+ }
137
+ async listReposPage(backend, params) {
138
+ const { limit, offset } = parseListReposPagination(params, {
139
+ defaultLimit: LIST_REPOS_DEFAULT_LIMIT,
140
+ maxLimit: LIST_REPOS_MAX_LIMIT,
141
+ });
142
+ const repositories = await this.listAllowedRepos(backend);
143
+ repositories.sort((a, b) => {
144
+ const an = a.name.toLowerCase();
145
+ const bn = b.name.toLowerCase();
146
+ if (an !== bn)
147
+ return an < bn ? -1 : 1;
148
+ return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
149
+ });
150
+ const total = repositories.length;
151
+ const page = repositories.slice(offset, offset + limit);
152
+ const returned = page.length;
153
+ const hasMore = offset + returned < total;
154
+ return {
155
+ repositories: page,
156
+ pagination: {
157
+ total,
158
+ limit,
159
+ offset,
160
+ returned,
161
+ hasMore,
162
+ ...(hasMore && { nextOffset: offset + returned }),
163
+ },
164
+ };
165
+ }
166
+ async callTool(backend, method, params) {
167
+ if (!this.configured)
168
+ return backend.callTool(method, params);
169
+ if (method === 'list_repos')
170
+ return this.listReposPage(backend, params);
171
+ if (this.restricted && method.startsWith('group_')) {
172
+ throw new Error('Group tools are unavailable when an MCP repository allowlist is set.');
173
+ }
174
+ return backend.callTool(method, this.normalizeToolArgs(params));
175
+ }
176
+ async resolveRepo(backend, repo, branch) {
177
+ if (!this.configured)
178
+ return backend.resolveRepo(repo, branch);
179
+ if (!this.restricted)
180
+ return backend.resolveRepo(repo ?? this.defaultRepo?.path, branch);
181
+ const selected = this.repoForArgs(repo === undefined ? undefined : { repo });
182
+ return backend.resolveRepo(selected?.path, branch);
183
+ }
184
+ assertResourceUri(uri) {
185
+ if (!this.restricted)
186
+ return;
187
+ let parsed;
188
+ try {
189
+ parsed = new URL(uri);
190
+ }
191
+ catch {
192
+ // resources.ts parses with the same URL call, so anything that fails
193
+ // here fails there too today. Keep obviously group- or repo-shaped
194
+ // malformed inputs fail-closed anyway in case the parsers ever drift.
195
+ if (/^gitnexus:\/\/group(?:\/|$)/iu.test(uri)) {
196
+ throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
197
+ }
198
+ const repoShaped = /^gitnexus:\/\/repo\/([^/]+)/iu.exec(uri);
199
+ if (repoShaped)
200
+ this.resolveRuntimeRepo(decodeURIComponent(repoShaped[1]));
201
+ return;
202
+ }
203
+ // gitnexus: is a non-special URL scheme, so the host is opaque and NOT
204
+ // lowercased by the parser — compare case-insensitively like
205
+ // read-only-policy.ts does.
206
+ if (parsed.protocol.toLowerCase() !== 'gitnexus:')
207
+ return;
208
+ const hostname = parsed.hostname.toLowerCase();
209
+ if (hostname === 'group') {
210
+ throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
211
+ }
212
+ if (hostname !== 'repo')
213
+ return;
214
+ const repoName = parsed.pathname.split('/').filter(Boolean)[0];
215
+ if (!repoName)
216
+ return;
217
+ this.resolveRuntimeRepo(decodeURIComponent(repoName));
218
+ }
219
+ resourceTemplateAllowed(uriTemplate) {
220
+ return !this.restricted || !uriTemplate.startsWith('gitnexus://group/');
221
+ }
222
+ toolAllowed(toolName) {
223
+ return !this.restricted || !toolName.startsWith('group_');
224
+ }
225
+ toolForMcp(tool) {
226
+ if (!this.restricted)
227
+ return tool;
228
+ const properties = { ...tool.inputSchema.properties };
229
+ const repo = properties.repo;
230
+ if (repo && typeof repo === 'object') {
231
+ properties.repo = {
232
+ ...repo,
233
+ description: 'Allowed indexed repository name or path. Group-mode values are unavailable.',
234
+ };
235
+ }
236
+ delete properties.subgroup;
237
+ delete properties.crossDepth;
238
+ const description = scrubGroupDescription(tool.description);
239
+ return { ...tool, description, inputSchema: { ...tool.inputSchema, properties } };
240
+ }
241
+ scopeBackend(backend) {
242
+ const policy = this;
243
+ return new Proxy(backend, {
244
+ get(target, property, receiver) {
245
+ if (property === 'callTool') {
246
+ return (method, params) => policy.callTool(target, method, params);
247
+ }
248
+ if (property === 'listRepos')
249
+ return () => policy.listAllowedRepos(target);
250
+ if (property === 'resolveRepo') {
251
+ return (repo, branch) => policy.resolveRepo(target, repo, branch);
252
+ }
253
+ if (property === 'getContext' && policy.restricted) {
254
+ return (repoId) => {
255
+ if (!repoId || !policy.uniqueAllowedContextNames.has(repoId.toLowerCase()))
256
+ return null;
257
+ return target.getContext(repoId);
258
+ };
259
+ }
260
+ if (policy.restricted &&
261
+ (property === 'readGroupContractsResource' || property === 'readGroupStatusResource')) {
262
+ return async () => {
263
+ throw new Error('Group resources are unavailable when an MCP repository allowlist is set.');
264
+ };
265
+ }
266
+ // Repo-scoped resource reads must not depend on assertResourceUri
267
+ // running first — enforce the allowlist on the query surface too.
268
+ if (policy.restricted && (property === 'queryClusters' || property === 'queryProcesses')) {
269
+ return (repoName, limit) => {
270
+ const selected = policy.repoForArgs(repoName === undefined ? undefined : { repo: repoName });
271
+ return property === 'queryClusters'
272
+ ? target.queryClusters(selected?.path ?? repoName, limit)
273
+ : target.queryProcesses(selected?.path ?? repoName, limit);
274
+ };
275
+ }
276
+ if (policy.restricted &&
277
+ (property === 'queryClusterDetail' || property === 'queryProcessDetail')) {
278
+ return (name, repoName) => {
279
+ const selected = policy.repoForArgs(repoName === undefined ? undefined : { repo: repoName });
280
+ return property === 'queryClusterDetail'
281
+ ? target.queryClusterDetail(name, selected?.path ?? repoName)
282
+ : target.queryProcessDetail(name, selected?.path ?? repoName);
283
+ };
284
+ }
285
+ const value = Reflect.get(target, property, receiver);
286
+ return typeof value === 'function' ? value.bind(target) : value;
287
+ },
288
+ });
289
+ }
290
+ }
291
+ export function mcpRepositoryPolicyConfigured(env = process.env) {
292
+ const raw = parseRepositoryPolicy(env);
293
+ return raw.allowed !== undefined || raw.defaultRepo !== undefined;
294
+ }
295
+ export async function createMcpRepositoryPolicy(backend, env = process.env) {
296
+ const raw = parseRepositoryPolicy(env);
297
+ if (!raw.allowed && !raw.defaultRepo) {
298
+ return McpRepositoryPolicy.unrestricted();
299
+ }
300
+ const registry = (await backend.listRepos()).map((repo) => ({
301
+ name: repo.name,
302
+ path: repo.path,
303
+ pathKey: normalizedPath(repo.path),
304
+ }));
305
+ let allowed;
306
+ if (raw.allowed) {
307
+ const byPath = new Map();
308
+ for (const specifier of raw.allowed) {
309
+ const result = resolveSpecifier(specifier, registry);
310
+ if (!result.repo)
311
+ throw startupResolutionError(result.reason ?? 'invalid');
312
+ byPath.set(result.repo.pathKey, result.repo);
313
+ }
314
+ allowed = [...byPath.values()];
315
+ }
316
+ let defaultRepo;
317
+ if (raw.defaultRepo) {
318
+ const result = resolveSpecifier(raw.defaultRepo, registry);
319
+ if (!result.repo)
320
+ throw startupResolutionError(result.reason ?? 'invalid');
321
+ defaultRepo = result.repo;
322
+ }
323
+ const defaultPathKey = defaultRepo?.pathKey;
324
+ if (defaultPathKey && allowed && !allowed.some((repo) => repo.pathKey === defaultPathKey)) {
325
+ throw new Error('The MCP default repository is not in the configured allowlist.');
326
+ }
327
+ return new McpRepositoryPolicy(registry, allowed, defaultRepo);
328
+ }
@@ -5,6 +5,9 @@
5
5
  * All resources use repo-scoped URIs: gitnexus://repo/{name}/context
6
6
  */
7
7
  import { checkStaleness } from './staleness.js';
8
+ import { loadMeta } from '../storage/repo-manager.js';
9
+ import { ANALYZER_RUNNER_IDENTITY_SCHEMA_VERSION } from '../core/analyzer-identity.js';
10
+ import { getIndexIncompleteReasons } from '../core/index-freshness.js';
8
11
  /**
9
12
  * Static resources — includes per-repo resources and the global repos list
10
13
  */
@@ -249,9 +252,16 @@ async function getContextResource(backend, repoName) {
249
252
  if (!context) {
250
253
  return 'error: No codebase loaded. Run: gitnexus analyze';
251
254
  }
252
- // Check staleness
255
+ // Read fresh metadata from disk on every context resource read to avoid showing
256
+ // a stale staleness banner or outdated stats after an out-of-process
257
+ // `analyze --index-only` refresh. The RepoHandle is cached in-memory and only
258
+ // refreshes on registry misses, so its lastCommit/stats can lag behind the
259
+ // on-disk state (#2438). Mirrors the ensureInitialized hot-swap pattern.
260
+ const freshMeta = await loadMeta(repo.storagePath).catch(() => null);
261
+ const incompleteReasons = getIndexIncompleteReasons(freshMeta);
262
+ // Check staleness using the current on-disk lastCommit (not the cached handle)
253
263
  const repoPath = repo.repoPath;
254
- const lastCommit = repo.lastCommit || 'HEAD';
264
+ const lastCommit = freshMeta?.lastCommit ?? repo.lastCommit ?? 'HEAD';
255
265
  const staleness = repoPath
256
266
  ? checkStaleness(repoPath, lastCommit)
257
267
  : { isStale: false, commitsBehind: 0 };
@@ -260,11 +270,27 @@ async function getContextResource(backend, repoName) {
260
270
  lines.push('');
261
271
  lines.push(`staleness: "${staleness.hint}"`);
262
272
  }
273
+ // A JSON object is also a valid YAML flow mapping. Keeping the versioned
274
+ // receipt intact lets agents compare every identity field without parsing a
275
+ // lossy human rendering; null explicitly means legacy/unknown provenance.
276
+ lines.push('');
277
+ lines.push('index:');
278
+ lines.push(` commit: ${JSON.stringify(lastCommit)}`);
279
+ lines.push(` indexed_at: ${JSON.stringify(freshMeta?.indexedAt ?? null)}`);
280
+ lines.push(` runner_identity: ${JSON.stringify(freshMeta?.runnerIdentity ?? null)}`);
281
+ lines.push(` incomplete_reasons: ${JSON.stringify(incompleteReasons)}`);
282
+ const indexedRunnerSchema = freshMeta?.runnerIdentity
283
+ ?.schemaVersion;
284
+ lines.push(` runner_identity_schema_status: ${JSON.stringify(indexedRunnerSchema === ANALYZER_RUNNER_IDENTITY_SCHEMA_VERSION
285
+ ? 'current'
286
+ : 'legacy-or-unknown')}`);
287
+ // Use fresh stats from disk meta when available; fall back to cached context
288
+ const freshStats = freshMeta?.stats;
263
289
  lines.push('');
264
290
  lines.push('stats:');
265
- lines.push(` files: ${context.stats.fileCount}`);
266
- lines.push(` symbols: ${context.stats.functionCount}`);
267
- lines.push(` processes: ${context.stats.processCount}`);
291
+ lines.push(` files: ${freshStats?.files ?? context.stats.fileCount}`);
292
+ lines.push(` symbols: ${freshStats?.nodes ?? context.stats.functionCount}`);
293
+ lines.push(` processes: ${freshStats?.processes ?? context.stats.processCount}`);
268
294
  lines.push('');
269
295
  lines.push('tools_available:');
270
296
  lines.push(' - query: Process-grouped code intelligence (execution flows related to a concept)');
@@ -365,6 +391,7 @@ additional_node_types: "Multi-language: Struct, Enum, Macro, Typedef, Union, Nam
365
391
 
366
392
  node_properties:
367
393
  common: "name (STRING), filePath (STRING), startLine (INT32), endLine (INT32)"
394
+ line_numbers: "startLine/endLine on symbol nodes are 0-BASED (tree-sitter rows) in storage AND in raw Cypher results. The context, query, impact, group/cross-repo trace, and explain/pdg_query (symbol anchor) tools present them 1-BASED (editor / sed / less -N aligned), so a symbol spans editor lines (startLine+1)..(endLine+1) — e.g. sed '<startLine+1>,<endLine+1>!d' <file>. Single-repo trace symbol lines stay 0-BASED for now (full-parity follow-up). content holds the exact symbol span. (BasicBlock / PDG statement lines are separately 1-based.) (#2377, #2380)"
368
395
  Method: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isVirtual (BOOL), isOverride (BOOL), isAsync (BOOL), isPartial (BOOL), requiredParameterCount (INT32), parameterTypes (STRING[]), annotations (STRING[])"
369
396
  Function: "parameterCount (INT32), returnType (STRING), isVariadic (BOOL), visibility (STRING), isStatic (BOOL), isAbstract (BOOL), isFinal (BOOL), isAsync (BOOL), parameterTypes (STRING[]), annotations (STRING[])"
370
397
  Property: "declaredType (STRING) — the field's type annotation (e.g., 'Address', 'City'). Used for field-access chain resolution."