contextpro-mcp 0.0.0-stage → 1.4.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 (466) hide show
  1. package/CHANGELOG.md +416 -0
  2. package/INSTALL.md +128 -0
  3. package/INSTRUCTIONS.md +33 -0
  4. package/LICENSE +21 -0
  5. package/NOTICE +12 -0
  6. package/README.md +164 -2
  7. package/SECURITY.md +27 -0
  8. package/agent-guide.md +323 -0
  9. package/agent-instructions.md +1 -0
  10. package/build/core/agent-setup.d.ts +5 -0
  11. package/build/core/agent-setup.d.ts.map +1 -0
  12. package/build/core/agent-setup.js +94 -0
  13. package/build/core/agent-setup.js.map +1 -0
  14. package/build/core/artifacts.d.ts +64 -0
  15. package/build/core/artifacts.d.ts.map +1 -0
  16. package/build/core/artifacts.js +370 -0
  17. package/build/core/artifacts.js.map +1 -0
  18. package/build/core/bounded-source.d.ts +15 -0
  19. package/build/core/bounded-source.d.ts.map +1 -0
  20. package/build/core/bounded-source.js +78 -0
  21. package/build/core/bounded-source.js.map +1 -0
  22. package/build/core/changed-since.d.ts +20 -0
  23. package/build/core/changed-since.d.ts.map +1 -0
  24. package/build/core/changed-since.js +43 -0
  25. package/build/core/changed-since.js.map +1 -0
  26. package/build/core/chat-model.d.ts +8 -0
  27. package/build/core/chat-model.d.ts.map +1 -0
  28. package/build/core/chat-model.js +135 -0
  29. package/build/core/chat-model.js.map +1 -0
  30. package/build/core/clustering.d.ts +6 -0
  31. package/build/core/clustering.d.ts.map +1 -0
  32. package/build/core/clustering.js +201 -0
  33. package/build/core/clustering.js.map +1 -0
  34. package/build/core/context-metadata.d.ts +50 -0
  35. package/build/core/context-metadata.d.ts.map +1 -0
  36. package/build/core/context-metadata.js +118 -0
  37. package/build/core/context-metadata.js.map +1 -0
  38. package/build/core/data-dir.d.ts +5 -0
  39. package/build/core/data-dir.d.ts.map +1 -0
  40. package/build/core/data-dir.js +53 -0
  41. package/build/core/data-dir.js.map +1 -0
  42. package/build/core/db-native.d.ts +28 -0
  43. package/build/core/db-native.d.ts.map +1 -0
  44. package/build/core/db-native.js +120 -0
  45. package/build/core/db-native.js.map +1 -0
  46. package/build/core/db.d.ts +294 -0
  47. package/build/core/db.d.ts.map +1 -0
  48. package/build/core/db.js +1047 -0
  49. package/build/core/db.js.map +1 -0
  50. package/build/core/doctor.d.ts +13 -0
  51. package/build/core/doctor.d.ts.map +1 -0
  52. package/build/core/doctor.js +55 -0
  53. package/build/core/doctor.js.map +1 -0
  54. package/build/core/efficiency.d.ts +16 -0
  55. package/build/core/efficiency.d.ts.map +1 -0
  56. package/build/core/efficiency.js +170 -0
  57. package/build/core/efficiency.js.map +1 -0
  58. package/build/core/embedding-tracker.d.ts +25 -0
  59. package/build/core/embedding-tracker.d.ts.map +1 -0
  60. package/build/core/embedding-tracker.js +228 -0
  61. package/build/core/embedding-tracker.js.map +1 -0
  62. package/build/core/embeddings.d.ts +90 -0
  63. package/build/core/embeddings.d.ts.map +1 -0
  64. package/build/core/embeddings.js +693 -0
  65. package/build/core/embeddings.js.map +1 -0
  66. package/build/core/evidence-state.d.ts +42 -0
  67. package/build/core/evidence-state.d.ts.map +1 -0
  68. package/build/core/evidence-state.js +153 -0
  69. package/build/core/evidence-state.js.map +1 -0
  70. package/build/core/extractor-stamp.d.ts +10 -0
  71. package/build/core/extractor-stamp.d.ts.map +1 -0
  72. package/build/core/extractor-stamp.js +51 -0
  73. package/build/core/extractor-stamp.js.map +1 -0
  74. package/build/core/feature-brief-cache.d.ts +37 -0
  75. package/build/core/feature-brief-cache.d.ts.map +1 -0
  76. package/build/core/feature-brief-cache.js +100 -0
  77. package/build/core/feature-brief-cache.js.map +1 -0
  78. package/build/core/file-fingerprint.d.ts +15 -0
  79. package/build/core/file-fingerprint.d.ts.map +1 -0
  80. package/build/core/file-fingerprint.js +24 -0
  81. package/build/core/file-fingerprint.js.map +1 -0
  82. package/build/core/graph-analytics.d.ts +46 -0
  83. package/build/core/graph-analytics.d.ts.map +1 -0
  84. package/build/core/graph-analytics.js +371 -0
  85. package/build/core/graph-analytics.js.map +1 -0
  86. package/build/core/hub.d.ts +23 -0
  87. package/build/core/hub.d.ts.map +1 -0
  88. package/build/core/hub.js +123 -0
  89. package/build/core/hub.js.map +1 -0
  90. package/build/core/ignore-dirs.d.ts +7 -0
  91. package/build/core/ignore-dirs.d.ts.map +1 -0
  92. package/build/core/ignore-dirs.js +84 -0
  93. package/build/core/ignore-dirs.js.map +1 -0
  94. package/build/core/index-freshness.d.ts +15 -0
  95. package/build/core/index-freshness.d.ts.map +1 -0
  96. package/build/core/index-freshness.js +96 -0
  97. package/build/core/index-freshness.js.map +1 -0
  98. package/build/core/index-reconcile.d.ts +28 -0
  99. package/build/core/index-reconcile.d.ts.map +1 -0
  100. package/build/core/index-reconcile.js +129 -0
  101. package/build/core/index-reconcile.js.map +1 -0
  102. package/build/core/local-daemon.d.ts +5 -0
  103. package/build/core/local-daemon.d.ts.map +1 -0
  104. package/build/core/local-daemon.js +282 -0
  105. package/build/core/local-daemon.js.map +1 -0
  106. package/build/core/memory-graph.d.ts +68 -0
  107. package/build/core/memory-graph.d.ts.map +1 -0
  108. package/build/core/memory-graph.js +152 -0
  109. package/build/core/memory-graph.js.map +1 -0
  110. package/build/core/native-repair.d.ts +12 -0
  111. package/build/core/native-repair.d.ts.map +1 -0
  112. package/build/core/native-repair.js +167 -0
  113. package/build/core/native-repair.js.map +1 -0
  114. package/build/core/native-runtime.d.ts +12 -0
  115. package/build/core/native-runtime.d.ts.map +1 -0
  116. package/build/core/native-runtime.js +38 -0
  117. package/build/core/native-runtime.js.map +1 -0
  118. package/build/core/pagerank.d.ts +29 -0
  119. package/build/core/pagerank.d.ts.map +1 -0
  120. package/build/core/pagerank.js +90 -0
  121. package/build/core/pagerank.js.map +1 -0
  122. package/build/core/parser-process.d.ts +21 -0
  123. package/build/core/parser-process.d.ts.map +1 -0
  124. package/build/core/parser-process.js +103 -0
  125. package/build/core/parser-process.js.map +1 -0
  126. package/build/core/parser-worker.d.ts +2 -0
  127. package/build/core/parser-worker.d.ts.map +1 -0
  128. package/build/core/parser-worker.js +17 -0
  129. package/build/core/parser-worker.js.map +1 -0
  130. package/build/core/parser.d.ts +66 -0
  131. package/build/core/parser.d.ts.map +1 -0
  132. package/build/core/parser.js +750 -0
  133. package/build/core/parser.js.map +1 -0
  134. package/build/core/path-guard.d.ts +6 -0
  135. package/build/core/path-guard.d.ts.map +1 -0
  136. package/build/core/path-guard.js +55 -0
  137. package/build/core/path-guard.js.map +1 -0
  138. package/build/core/process-lifecycle.d.ts +30 -0
  139. package/build/core/process-lifecycle.d.ts.map +1 -0
  140. package/build/core/process-lifecycle.js +129 -0
  141. package/build/core/process-lifecycle.js.map +1 -0
  142. package/build/core/project-config.d.ts +83 -0
  143. package/build/core/project-config.d.ts.map +1 -0
  144. package/build/core/project-config.js +302 -0
  145. package/build/core/project-config.js.map +1 -0
  146. package/build/core/project-graph.d.ts +69 -0
  147. package/build/core/project-graph.d.ts.map +1 -0
  148. package/build/core/project-graph.js +874 -0
  149. package/build/core/project-graph.js.map +1 -0
  150. package/build/core/provider-config.d.ts +15 -0
  151. package/build/core/provider-config.d.ts.map +1 -0
  152. package/build/core/provider-config.js +67 -0
  153. package/build/core/provider-config.js.map +1 -0
  154. package/build/core/provider-usage.d.ts +21 -0
  155. package/build/core/provider-usage.d.ts.map +1 -0
  156. package/build/core/provider-usage.js +52 -0
  157. package/build/core/provider-usage.js.map +1 -0
  158. package/build/core/python-language-server.d.ts +23 -0
  159. package/build/core/python-language-server.d.ts.map +1 -0
  160. package/build/core/python-language-server.js +217 -0
  161. package/build/core/python-language-server.js.map +1 -0
  162. package/build/core/python-runtime-identity.d.ts +3 -0
  163. package/build/core/python-runtime-identity.d.ts.map +1 -0
  164. package/build/core/python-runtime-identity.js +53 -0
  165. package/build/core/python-runtime-identity.js.map +1 -0
  166. package/build/core/reconcile-scheduler.d.ts +20 -0
  167. package/build/core/reconcile-scheduler.d.ts.map +1 -0
  168. package/build/core/reconcile-scheduler.js +58 -0
  169. package/build/core/reconcile-scheduler.js.map +1 -0
  170. package/build/core/request-context.d.ts +7 -0
  171. package/build/core/request-context.d.ts.map +1 -0
  172. package/build/core/request-context.js +17 -0
  173. package/build/core/request-context.js.map +1 -0
  174. package/build/core/request-root.d.ts +19 -0
  175. package/build/core/request-root.d.ts.map +1 -0
  176. package/build/core/request-root.js +26 -0
  177. package/build/core/request-root.js.map +1 -0
  178. package/build/core/root-guard.d.ts +8 -0
  179. package/build/core/root-guard.d.ts.map +1 -0
  180. package/build/core/root-guard.js +53 -0
  181. package/build/core/root-guard.js.map +1 -0
  182. package/build/core/roots-detect.d.ts +17 -0
  183. package/build/core/roots-detect.d.ts.map +1 -0
  184. package/build/core/roots-detect.js +63 -0
  185. package/build/core/roots-detect.js.map +1 -0
  186. package/build/core/runtime-session.d.ts +5 -0
  187. package/build/core/runtime-session.d.ts.map +1 -0
  188. package/build/core/runtime-session.js +10 -0
  189. package/build/core/runtime-session.js.map +1 -0
  190. package/build/core/scip-index.d.ts +71 -0
  191. package/build/core/scip-index.d.ts.map +1 -0
  192. package/build/core/scip-index.js +343 -0
  193. package/build/core/scip-index.js.map +1 -0
  194. package/build/core/semantic-diff.d.ts +32 -0
  195. package/build/core/semantic-diff.d.ts.map +1 -0
  196. package/build/core/semantic-diff.js +259 -0
  197. package/build/core/semantic-diff.js.map +1 -0
  198. package/build/core/source-context.d.ts +3 -0
  199. package/build/core/source-context.d.ts.map +1 -0
  200. package/build/core/source-context.js +86 -0
  201. package/build/core/source-context.js.map +1 -0
  202. package/build/core/source-mask.d.ts +8 -0
  203. package/build/core/source-mask.d.ts.map +1 -0
  204. package/build/core/source-mask.js +156 -0
  205. package/build/core/source-mask.js.map +1 -0
  206. package/build/core/source-mutation.d.ts +16 -0
  207. package/build/core/source-mutation.d.ts.map +1 -0
  208. package/build/core/source-mutation.js +193 -0
  209. package/build/core/source-mutation.js.map +1 -0
  210. package/build/core/sql-schema.d.ts +59 -0
  211. package/build/core/sql-schema.d.ts.map +1 -0
  212. package/build/core/sql-schema.js +218 -0
  213. package/build/core/sql-schema.js.map +1 -0
  214. package/build/core/startup-health.d.ts +40 -0
  215. package/build/core/startup-health.d.ts.map +1 -0
  216. package/build/core/startup-health.js +132 -0
  217. package/build/core/startup-health.js.map +1 -0
  218. package/build/core/team-ledger.d.ts +60 -0
  219. package/build/core/team-ledger.d.ts.map +1 -0
  220. package/build/core/team-ledger.js +171 -0
  221. package/build/core/team-ledger.js.map +1 -0
  222. package/build/core/test-impact.d.ts +23 -0
  223. package/build/core/test-impact.d.ts.map +1 -0
  224. package/build/core/test-impact.js +131 -0
  225. package/build/core/test-impact.js.map +1 -0
  226. package/build/core/tool-metrics.d.ts +29 -0
  227. package/build/core/tool-metrics.d.ts.map +1 -0
  228. package/build/core/tool-metrics.js +74 -0
  229. package/build/core/tool-metrics.js.map +1 -0
  230. package/build/core/tool-profile.d.ts +12 -0
  231. package/build/core/tool-profile.d.ts.map +1 -0
  232. package/build/core/tool-profile.js +102 -0
  233. package/build/core/tool-profile.js.map +1 -0
  234. package/build/core/tool-trace.d.ts +8 -0
  235. package/build/core/tool-trace.d.ts.map +1 -0
  236. package/build/core/tool-trace.js +70 -0
  237. package/build/core/tool-trace.js.map +1 -0
  238. package/build/core/tree-sitter-runtime.d.ts +20 -0
  239. package/build/core/tree-sitter-runtime.d.ts.map +1 -0
  240. package/build/core/tree-sitter-runtime.js +324 -0
  241. package/build/core/tree-sitter-runtime.js.map +1 -0
  242. package/build/core/tree-sitter.d.ts +6 -0
  243. package/build/core/tree-sitter.d.ts.map +1 -0
  244. package/build/core/tree-sitter.js +24 -0
  245. package/build/core/tree-sitter.js.map +1 -0
  246. package/build/core/typescript-reference-process.d.ts +30 -0
  247. package/build/core/typescript-reference-process.d.ts.map +1 -0
  248. package/build/core/typescript-reference-process.js +124 -0
  249. package/build/core/typescript-reference-process.js.map +1 -0
  250. package/build/core/typescript-reference-worker.d.ts +2 -0
  251. package/build/core/typescript-reference-worker.d.ts.map +1 -0
  252. package/build/core/typescript-reference-worker.js +14 -0
  253. package/build/core/typescript-reference-worker.js.map +1 -0
  254. package/build/core/typescript-references.d.ts +71 -0
  255. package/build/core/typescript-references.d.ts.map +1 -0
  256. package/build/core/typescript-references.js +392 -0
  257. package/build/core/typescript-references.js.map +1 -0
  258. package/build/core/typescript-skeleton.d.ts +5 -0
  259. package/build/core/typescript-skeleton.d.ts.map +1 -0
  260. package/build/core/typescript-skeleton.js +49 -0
  261. package/build/core/typescript-skeleton.js.map +1 -0
  262. package/build/core/walker.d.ts +16 -0
  263. package/build/core/walker.d.ts.map +1 -0
  264. package/build/core/walker.js +152 -0
  265. package/build/core/walker.js.map +1 -0
  266. package/build/core/workspace-router.d.ts +28 -0
  267. package/build/core/workspace-router.d.ts.map +1 -0
  268. package/build/core/workspace-router.js +93 -0
  269. package/build/core/workspace-router.js.map +1 -0
  270. package/build/core/worktree-gc.d.ts +16 -0
  271. package/build/core/worktree-gc.d.ts.map +1 -0
  272. package/build/core/worktree-gc.js +69 -0
  273. package/build/core/worktree-gc.js.map +1 -0
  274. package/build/core/worktree-overlay.d.ts +22 -0
  275. package/build/core/worktree-overlay.d.ts.map +1 -0
  276. package/build/core/worktree-overlay.js +84 -0
  277. package/build/core/worktree-overlay.js.map +1 -0
  278. package/build/core/worktree-root-guard.d.ts +8 -0
  279. package/build/core/worktree-root-guard.d.ts.map +1 -0
  280. package/build/core/worktree-root-guard.js +82 -0
  281. package/build/core/worktree-root-guard.js.map +1 -0
  282. package/build/core/worktree-seed.d.ts +14 -0
  283. package/build/core/worktree-seed.d.ts.map +1 -0
  284. package/build/core/worktree-seed.js +98 -0
  285. package/build/core/worktree-seed.js.map +1 -0
  286. package/build/git/shadow.d.ts +40 -0
  287. package/build/git/shadow.d.ts.map +1 -0
  288. package/build/git/shadow.js +298 -0
  289. package/build/git/shadow.js.map +1 -0
  290. package/build/index.d.ts +3 -0
  291. package/build/index.d.ts.map +1 -0
  292. package/build/index.js +599 -0
  293. package/build/index.js.map +1 -0
  294. package/build/tools/agentic-context.d.ts +86 -0
  295. package/build/tools/agentic-context.d.ts.map +1 -0
  296. package/build/tools/agentic-context.js +1546 -0
  297. package/build/tools/agentic-context.js.map +1 -0
  298. package/build/tools/blast-radius.d.ts +24 -0
  299. package/build/tools/blast-radius.d.ts.map +1 -0
  300. package/build/tools/blast-radius.js +231 -0
  301. package/build/tools/blast-radius.js.map +1 -0
  302. package/build/tools/changed-since.d.ts +7 -0
  303. package/build/tools/changed-since.d.ts.map +1 -0
  304. package/build/tools/changed-since.js +68 -0
  305. package/build/tools/changed-since.js.map +1 -0
  306. package/build/tools/compiler-actions.d.ts +26 -0
  307. package/build/tools/compiler-actions.d.ts.map +1 -0
  308. package/build/tools/compiler-actions.js +121 -0
  309. package/build/tools/compiler-actions.js.map +1 -0
  310. package/build/tools/context-tree.d.ts +9 -0
  311. package/build/tools/context-tree.d.ts.map +1 -0
  312. package/build/tools/context-tree.js +131 -0
  313. package/build/tools/context-tree.js.map +1 -0
  314. package/build/tools/context.d.ts +37 -0
  315. package/build/tools/context.d.ts.map +1 -0
  316. package/build/tools/context.js +800 -0
  317. package/build/tools/context.js.map +1 -0
  318. package/build/tools/diff.d.ts +9 -0
  319. package/build/tools/diff.d.ts.map +1 -0
  320. package/build/tools/diff.js +176 -0
  321. package/build/tools/diff.js.map +1 -0
  322. package/build/tools/directory-prior.d.ts +16 -0
  323. package/build/tools/directory-prior.d.ts.map +1 -0
  324. package/build/tools/directory-prior.js +121 -0
  325. package/build/tools/directory-prior.js.map +1 -0
  326. package/build/tools/discovery-documents.d.ts +11 -0
  327. package/build/tools/discovery-documents.d.ts.map +1 -0
  328. package/build/tools/discovery-documents.js +71 -0
  329. package/build/tools/discovery-documents.js.map +1 -0
  330. package/build/tools/discovery-hints.d.ts +25 -0
  331. package/build/tools/discovery-hints.d.ts.map +1 -0
  332. package/build/tools/discovery-hints.js +329 -0
  333. package/build/tools/discovery-hints.js.map +1 -0
  334. package/build/tools/efficiency-report.d.ts +13 -0
  335. package/build/tools/efficiency-report.d.ts.map +1 -0
  336. package/build/tools/efficiency-report.js +78 -0
  337. package/build/tools/efficiency-report.js.map +1 -0
  338. package/build/tools/evidence-retrieval.d.ts +33 -0
  339. package/build/tools/evidence-retrieval.d.ts.map +1 -0
  340. package/build/tools/evidence-retrieval.js +200 -0
  341. package/build/tools/evidence-retrieval.js.map +1 -0
  342. package/build/tools/exact-references.d.ts +10 -0
  343. package/build/tools/exact-references.d.ts.map +1 -0
  344. package/build/tools/exact-references.js +349 -0
  345. package/build/tools/exact-references.js.map +1 -0
  346. package/build/tools/explain.d.ts +14 -0
  347. package/build/tools/explain.d.ts.map +1 -0
  348. package/build/tools/explain.js +370 -0
  349. package/build/tools/explain.js.map +1 -0
  350. package/build/tools/feature-brief.d.ts +7 -0
  351. package/build/tools/feature-brief.d.ts.map +1 -0
  352. package/build/tools/feature-brief.js +89 -0
  353. package/build/tools/feature-brief.js.map +1 -0
  354. package/build/tools/feature-hub.d.ts +15 -0
  355. package/build/tools/feature-hub.d.ts.map +1 -0
  356. package/build/tools/feature-hub.js +404 -0
  357. package/build/tools/feature-hub.js.map +1 -0
  358. package/build/tools/file-skeleton.d.ts +7 -0
  359. package/build/tools/file-skeleton.d.ts.map +1 -0
  360. package/build/tools/file-skeleton.js +190 -0
  361. package/build/tools/file-skeleton.js.map +1 -0
  362. package/build/tools/grep.d.ts +25 -0
  363. package/build/tools/grep.d.ts.map +1 -0
  364. package/build/tools/grep.js +341 -0
  365. package/build/tools/grep.js.map +1 -0
  366. package/build/tools/impact-delta.d.ts +7 -0
  367. package/build/tools/impact-delta.d.ts.map +1 -0
  368. package/build/tools/impact-delta.js +102 -0
  369. package/build/tools/impact-delta.js.map +1 -0
  370. package/build/tools/memory-tools.d.ts +69 -0
  371. package/build/tools/memory-tools.d.ts.map +1 -0
  372. package/build/tools/memory-tools.js +366 -0
  373. package/build/tools/memory-tools.js.map +1 -0
  374. package/build/tools/planning-helpers.d.ts +26 -0
  375. package/build/tools/planning-helpers.d.ts.map +1 -0
  376. package/build/tools/planning-helpers.js +269 -0
  377. package/build/tools/planning-helpers.js.map +1 -0
  378. package/build/tools/project-graph.d.ts +19 -0
  379. package/build/tools/project-graph.d.ts.map +1 -0
  380. package/build/tools/project-graph.js +259 -0
  381. package/build/tools/project-graph.js.map +1 -0
  382. package/build/tools/propose-commit.d.ts +9 -0
  383. package/build/tools/propose-commit.d.ts.map +1 -0
  384. package/build/tools/propose-commit.js +156 -0
  385. package/build/tools/propose-commit.js.map +1 -0
  386. package/build/tools/register-tools.d.ts +18 -0
  387. package/build/tools/register-tools.d.ts.map +1 -0
  388. package/build/tools/register-tools.js +1131 -0
  389. package/build/tools/register-tools.js.map +1 -0
  390. package/build/tools/reindex.d.ts +76 -0
  391. package/build/tools/reindex.d.ts.map +1 -0
  392. package/build/tools/reindex.js +871 -0
  393. package/build/tools/reindex.js.map +1 -0
  394. package/build/tools/related.d.ts +6 -0
  395. package/build/tools/related.d.ts.map +1 -0
  396. package/build/tools/related.js +143 -0
  397. package/build/tools/related.js.map +1 -0
  398. package/build/tools/repo-map.d.ts +59 -0
  399. package/build/tools/repo-map.d.ts.map +1 -0
  400. package/build/tools/repo-map.js +270 -0
  401. package/build/tools/repo-map.js.map +1 -0
  402. package/build/tools/resolve-symbol.d.ts +41 -0
  403. package/build/tools/resolve-symbol.d.ts.map +1 -0
  404. package/build/tools/resolve-symbol.js +250 -0
  405. package/build/tools/resolve-symbol.js.map +1 -0
  406. package/build/tools/retrieval-helpers.d.ts +35 -0
  407. package/build/tools/retrieval-helpers.d.ts.map +1 -0
  408. package/build/tools/retrieval-helpers.js +302 -0
  409. package/build/tools/retrieval-helpers.js.map +1 -0
  410. package/build/tools/scip-index.d.ts +12 -0
  411. package/build/tools/scip-index.d.ts.map +1 -0
  412. package/build/tools/scip-index.js +66 -0
  413. package/build/tools/scip-index.js.map +1 -0
  414. package/build/tools/scoped-discovery.d.ts +7 -0
  415. package/build/tools/scoped-discovery.d.ts.map +1 -0
  416. package/build/tools/scoped-discovery.js +89 -0
  417. package/build/tools/scoped-discovery.js.map +1 -0
  418. package/build/tools/search.d.ts +62 -0
  419. package/build/tools/search.d.ts.map +1 -0
  420. package/build/tools/search.js +419 -0
  421. package/build/tools/search.js.map +1 -0
  422. package/build/tools/semantic-diff.d.ts +7 -0
  423. package/build/tools/semantic-diff.d.ts.map +1 -0
  424. package/build/tools/semantic-diff.js +45 -0
  425. package/build/tools/semantic-diff.js.map +1 -0
  426. package/build/tools/semantic-identifiers.d.ts +51 -0
  427. package/build/tools/semantic-identifiers.d.ts.map +1 -0
  428. package/build/tools/semantic-identifiers.js +522 -0
  429. package/build/tools/semantic-identifiers.js.map +1 -0
  430. package/build/tools/semantic-navigate.d.ts +18 -0
  431. package/build/tools/semantic-navigate.d.ts.map +1 -0
  432. package/build/tools/semantic-navigate.js +413 -0
  433. package/build/tools/semantic-navigate.js.map +1 -0
  434. package/build/tools/semantic-search.d.ts +30 -0
  435. package/build/tools/semantic-search.d.ts.map +1 -0
  436. package/build/tools/semantic-search.js +466 -0
  437. package/build/tools/semantic-search.js.map +1 -0
  438. package/build/tools/sql-schema.d.ts +23 -0
  439. package/build/tools/sql-schema.d.ts.map +1 -0
  440. package/build/tools/sql-schema.js +155 -0
  441. package/build/tools/sql-schema.js.map +1 -0
  442. package/build/tools/static-analysis.d.ts +7 -0
  443. package/build/tools/static-analysis.d.ts.map +1 -0
  444. package/build/tools/static-analysis.js +331 -0
  445. package/build/tools/static-analysis.js.map +1 -0
  446. package/build/tools/status.d.ts +74 -0
  447. package/build/tools/status.d.ts.map +1 -0
  448. package/build/tools/status.js +227 -0
  449. package/build/tools/status.js.map +1 -0
  450. package/build/tools/symbolic-edit.d.ts +57 -0
  451. package/build/tools/symbolic-edit.d.ts.map +1 -0
  452. package/build/tools/symbolic-edit.js +500 -0
  453. package/build/tools/symbolic-edit.js.map +1 -0
  454. package/build/tools/test-impact.d.ts +7 -0
  455. package/build/tools/test-impact.d.ts.map +1 -0
  456. package/build/tools/test-impact.js +34 -0
  457. package/build/tools/test-impact.js.map +1 -0
  458. package/build/tools/test-map.d.ts +8 -0
  459. package/build/tools/test-map.d.ts.map +1 -0
  460. package/build/tools/test-map.js +75 -0
  461. package/build/tools/test-map.js.map +1 -0
  462. package/docs/README.md +26 -0
  463. package/docs/architecture.md +35 -0
  464. package/docs/configuration.md +178 -0
  465. package/docs/maintenance.md +77 -0
  466. package/package.json +80 -4
@@ -0,0 +1,874 @@
1
+ // Portable project graph builder from the SQLite index
2
+ // FEATURE: Exact code graph — typed nodes, edges, confidence, and export artifacts
3
+ import { createHash } from "crypto";
4
+ import { execFile } from "child_process";
5
+ import { mkdir } from "fs/promises";
6
+ import { dirname, posix } from "path";
7
+ import { promisify } from "util";
8
+ import { getDB } from "./db.js";
9
+ import { resolveProjectPath } from "./path-guard.js";
10
+ import { writeFileAtomic } from "./artifacts.js";
11
+ import { loadScipIndex, scipSymbolDisplayName, scipSymbolNodeId } from "./scip-index.js";
12
+ import { detectGraphCommunities, findWeightedShortestPath, rankGraphHotspots, } from "./graph-analytics.js";
13
+ const execFileAsync = promisify(execFile);
14
+ function stableId(parts) {
15
+ return createHash("sha1").update(parts.join("\0")).digest("hex").slice(0, 16);
16
+ }
17
+ const GRAPH_STRUCTURAL_KINDS = new Set(["function", "method", "class", "interface", "enum", "type", "struct", "trait", "export"]);
18
+ function isGraphRelevantSymbol(symbol, structuralRanges) {
19
+ if (GRAPH_STRUCTURAL_KINDS.has(symbol.kind))
20
+ return true;
21
+ if (symbol.kind !== "const" && symbol.kind !== "variable")
22
+ return false;
23
+ const sig = symbol.signature ?? "";
24
+ if (/^export\s/.test(sig))
25
+ return true;
26
+ if (symbol.parent_symbol_id != null)
27
+ return false;
28
+ for (const range of structuralRanges) {
29
+ if (symbol.line_start > range.start && symbol.line_start <= range.end)
30
+ return false;
31
+ }
32
+ if (symbol.name.length < 3)
33
+ return false;
34
+ return true;
35
+ }
36
+ function edgeId(type, source, target, evidence) {
37
+ return `edge:${stableId([type, source, target, evidence])}`;
38
+ }
39
+ function classifyPath(path) {
40
+ if (/\.(test|spec|demo)\.[^.]+$/.test(path) || /(^|\/)(__tests__|test|tests)\//.test(path))
41
+ return "test";
42
+ if (/(^|\/)(package\.json|tsconfig\.json|go\.mod|Cargo\.toml|pyproject\.toml|eslint\.config\.[cm]?js|\.eslintrc\.)/.test(path))
43
+ return "config";
44
+ if (/\.(md|mdx|txt|rst|adoc)$/.test(path))
45
+ return "document";
46
+ return "file";
47
+ }
48
+ function classifyFile(file) {
49
+ return classifyPath(file.path);
50
+ }
51
+ function basename(path) {
52
+ return path.split("/").filter(Boolean).at(-1) ?? path;
53
+ }
54
+ function addNode(nodes, node) {
55
+ if (!nodes.has(node.id))
56
+ nodes.set(node.id, node);
57
+ }
58
+ function addEdge(edges, edge) {
59
+ const id = edgeId(edge.type, edge.source, edge.target, edge.evidence);
60
+ if (!edges.has(id))
61
+ edges.set(id, { id, ...edge });
62
+ }
63
+ function fileNodeId(path) {
64
+ return `file:${path}`;
65
+ }
66
+ function folderNodeId(path) {
67
+ return `folder:${path || "."}`;
68
+ }
69
+ function symbolNodeId(filePath, symbol) {
70
+ return `symbol:${filePath}:${symbol.line_start}:${symbol.name}`;
71
+ }
72
+ function packageNodeId(specifier) {
73
+ return `package:${specifier}`;
74
+ }
75
+ function routeNodeId(route) {
76
+ return `route:${route}`;
77
+ }
78
+ function ensureFolderChain(nodes, edges, projectId, filePath) {
79
+ const parts = dirname(filePath).split("/").filter((part) => part !== ".");
80
+ let parentId = projectId;
81
+ let currentPath = "";
82
+ for (const part of parts) {
83
+ currentPath = currentPath ? `${currentPath}/${part}` : part;
84
+ const id = folderNodeId(currentPath);
85
+ addNode(nodes, { id, type: "folder", label: part, path: currentPath });
86
+ addEdge(edges, {
87
+ type: "contains",
88
+ source: parentId,
89
+ target: id,
90
+ confidence: "AST_EXTRACTED",
91
+ evidence: "path hierarchy",
92
+ });
93
+ parentId = id;
94
+ }
95
+ return parentId;
96
+ }
97
+ function parseImportedSymbols(raw) {
98
+ if (!raw)
99
+ return [];
100
+ try {
101
+ const parsed = JSON.parse(raw);
102
+ return Array.isArray(parsed) ? parsed.map((value) => String(value)) : [];
103
+ }
104
+ catch {
105
+ return [];
106
+ }
107
+ }
108
+ function testBase(path) {
109
+ return basename(path).replace(/\.(test|spec|demo)\.[^.]+$/, "").replace(/\.[^.]+$/, "");
110
+ }
111
+ function sourceBase(path) {
112
+ return basename(path).replace(/\.[^.]+$/, "");
113
+ }
114
+ function inferRoutePath(filePath) {
115
+ const normalized = filePath.replace(/\\/g, "/");
116
+ const withoutExt = normalized.replace(/\.[^.]+$/, "");
117
+ if (normalized.includes("/routes/")) {
118
+ const route = withoutExt.slice(withoutExt.indexOf("/routes/") + "/routes/".length);
119
+ return `/${route.replace(/\/index$/, "").replace(/\$/g, ":")}` || "/";
120
+ }
121
+ if (normalized.startsWith("routes/")) {
122
+ const route = withoutExt.slice("routes/".length);
123
+ return `/${route.replace(/\/index$/, "").replace(/\$/g, ":")}` || "/";
124
+ }
125
+ if (normalized.startsWith("pages/")) {
126
+ const route = withoutExt.slice("pages/".length);
127
+ if (route.startsWith("api/"))
128
+ return null;
129
+ return `/${route.replace(/\/index$/, "").replace(/index$/, "").replace(/\[(.+?)\]/g, ":$1")}` || "/";
130
+ }
131
+ const appPage = normalized.match(/^app\/(.+)\/page\.(tsx|ts|jsx|js)$/);
132
+ if (appPage)
133
+ return `/${appPage[1].replace(/\[(.+?)\]/g, ":$1")}`;
134
+ return null;
135
+ }
136
+ function relationTargets(signature, keyword) {
137
+ if (!signature)
138
+ return [];
139
+ const regex = keyword === "extends"
140
+ ? /\bextends\s+([A-Za-z_$][\w$]*)/
141
+ : /\bimplements\s+([A-Za-z_$][\w$]*(?:\s*,\s*[A-Za-z_$][\w$]*)*)/;
142
+ const match = signature.match(regex);
143
+ if (!match)
144
+ return [];
145
+ return match[1].split(",").map((value) => value.trim()).filter(Boolean);
146
+ }
147
+ async function collectCoChangePairs(rootDir, filesByPath) {
148
+ try {
149
+ const { stdout } = await execFileAsync("git", ["log", "--name-only", "--pretty=format:--contextplus-commit--", "-n", "200"], {
150
+ cwd: rootDir,
151
+ timeout: 8000,
152
+ maxBuffer: 1024 * 1024,
153
+ });
154
+ const counts = new Map();
155
+ let current = new Set();
156
+ const flush = () => {
157
+ const files = [...current].filter((path) => filesByPath.has(path)).sort();
158
+ current = new Set();
159
+ if (files.length < 2 || files.length > 20)
160
+ return;
161
+ for (let i = 0; i < files.length; i++) {
162
+ for (let j = i + 1; j < files.length; j++) {
163
+ const key = `${files[i]}\0${files[j]}`;
164
+ counts.set(key, (counts.get(key) ?? 0) + 1);
165
+ }
166
+ }
167
+ };
168
+ for (const line of stdout.split("\n")) {
169
+ const trimmed = line.trim();
170
+ if (trimmed === "--contextplus-commit--") {
171
+ flush();
172
+ continue;
173
+ }
174
+ if (trimmed.length > 0)
175
+ current.add(trimmed);
176
+ }
177
+ flush();
178
+ return [...counts.entries()]
179
+ .map(([key, count]) => {
180
+ const [left, right] = key.split("\0");
181
+ return { left, right, count };
182
+ })
183
+ .filter((pair) => pair.count >= 2)
184
+ .sort((a, b) => b.count - a.count || a.left.localeCompare(b.left))
185
+ .slice(0, 100);
186
+ }
187
+ catch {
188
+ return [];
189
+ }
190
+ }
191
+ function resolveRelativeImport(sourcePath, specifier, filesByPath) {
192
+ if (!specifier.startsWith("."))
193
+ return null;
194
+ const sourceDir = dirname(sourcePath);
195
+ const base = posix.normalize(sourceDir === "." ? specifier : `${sourceDir}/${specifier}`);
196
+ const candidates = [
197
+ base,
198
+ `${base}.ts`,
199
+ `${base}.tsx`,
200
+ `${base}.js`,
201
+ `${base}.jsx`,
202
+ base.replace(/\.js$/, ".ts"),
203
+ `${base}/index.ts`,
204
+ `${base}/index.tsx`,
205
+ `${base}/index.js`,
206
+ ];
207
+ for (const candidate of candidates) {
208
+ const found = filesByPath.get(candidate);
209
+ if (found)
210
+ return found;
211
+ }
212
+ return null;
213
+ }
214
+ const graphCache = new Map();
215
+ const MAX_GRAPH_CACHE_ROOTS = 50;
216
+ export async function buildProjectGraph(rootDir) {
217
+ const db = await getDB(rootDir);
218
+ const indexGeneration = db.getIndexGeneration();
219
+ const cached = graphCache.get(rootDir);
220
+ if (cached && cached.indexGeneration === indexGeneration) {
221
+ graphCache.delete(rootDir);
222
+ graphCache.set(rootDir, cached);
223
+ return cached.promise;
224
+ }
225
+ const promise = buildProjectGraphFromDB(rootDir, db);
226
+ graphCache.delete(rootDir);
227
+ graphCache.set(rootDir, { indexGeneration, promise });
228
+ while (graphCache.size > MAX_GRAPH_CACHE_ROOTS) {
229
+ const oldest = graphCache.keys().next().value;
230
+ if (!oldest)
231
+ break;
232
+ graphCache.delete(oldest);
233
+ }
234
+ try {
235
+ return await promise;
236
+ }
237
+ catch (error) {
238
+ if (graphCache.get(rootDir)?.promise === promise)
239
+ graphCache.delete(rootDir);
240
+ throw error;
241
+ }
242
+ }
243
+ export function invalidateProjectGraphCache(rootDir) {
244
+ if (rootDir)
245
+ graphCache.delete(rootDir);
246
+ else
247
+ graphCache.clear();
248
+ }
249
+ export async function buildProjectGraphFromDB(rootDir, db) {
250
+ const nodes = new Map();
251
+ const edges = new Map();
252
+ const files = db.getAllFiles().sort((a, b) => a.path.localeCompare(b.path));
253
+ const filesById = new Map(files.map((file) => [file.id, file]));
254
+ const filesByPath = new Map(files.map((file) => [file.path, file]));
255
+ const projectId = "project:root";
256
+ addNode(nodes, {
257
+ id: projectId,
258
+ type: "project",
259
+ label: basename(rootDir),
260
+ path: ".",
261
+ metadata: { rootDir },
262
+ });
263
+ const symbolsByFile = new Map();
264
+ const symbolsByName = new Map();
265
+ let symbolCount = 0;
266
+ for (const file of files) {
267
+ const parentId = ensureFolderChain(nodes, edges, projectId, file.path);
268
+ const nodeId = fileNodeId(file.path);
269
+ const type = classifyFile(file);
270
+ addNode(nodes, {
271
+ id: nodeId,
272
+ type,
273
+ label: basename(file.path),
274
+ path: file.path,
275
+ language: file.language,
276
+ metadata: {
277
+ contentHash: file.content_hash,
278
+ header: file.header,
279
+ size: file.file_size,
280
+ symbols: file.symbol_count,
281
+ },
282
+ });
283
+ addEdge(edges, {
284
+ type: "contains",
285
+ source: parentId,
286
+ target: nodeId,
287
+ confidence: "AST_EXTRACTED",
288
+ evidence: "path hierarchy",
289
+ });
290
+ if (type === "config") {
291
+ addEdge(edges, {
292
+ type: "configures",
293
+ source: nodeId,
294
+ target: projectId,
295
+ confidence: "HEURISTIC",
296
+ evidence: "config filename",
297
+ });
298
+ }
299
+ const routePath = inferRoutePath(file.path);
300
+ if (routePath) {
301
+ const routeId = routeNodeId(routePath);
302
+ addNode(nodes, { id: routeId, type: "route", label: routePath, path: routePath });
303
+ addEdge(edges, {
304
+ type: "route_handles",
305
+ source: nodeId,
306
+ target: routeId,
307
+ confidence: "HEURISTIC",
308
+ evidence: "route file path convention",
309
+ });
310
+ }
311
+ const symbols = db.getSymbolsByFile(file.id);
312
+ symbolsByFile.set(file.id, symbols);
313
+ symbolCount += symbols.length;
314
+ const structuralRanges = symbols
315
+ .filter((sym) => GRAPH_STRUCTURAL_KINDS.has(sym.kind))
316
+ .map((sym) => ({ start: sym.line_start, end: sym.line_end ?? sym.line_start }));
317
+ for (const symbol of symbols) {
318
+ if (!isGraphRelevantSymbol(symbol, structuralRanges))
319
+ continue;
320
+ const symbolId = symbolNodeId(file.path, symbol);
321
+ addNode(nodes, {
322
+ id: symbolId,
323
+ type: "symbol",
324
+ label: symbol.name,
325
+ path: file.path,
326
+ language: file.language,
327
+ lineStart: symbol.line_start,
328
+ lineEnd: symbol.line_end,
329
+ metadata: {
330
+ kind: symbol.kind,
331
+ signature: symbol.signature,
332
+ },
333
+ });
334
+ addEdge(edges, {
335
+ type: "defines",
336
+ source: nodeId,
337
+ target: symbolId,
338
+ confidence: "AST_EXTRACTED",
339
+ evidence: "tree-sitter symbol extraction",
340
+ });
341
+ const existing = symbolsByName.get(symbol.name) ?? [];
342
+ existing.push({ file, symbol, id: symbolId });
343
+ symbolsByName.set(symbol.name, existing);
344
+ }
345
+ }
346
+ for (const entriesForName of symbolsByName.values()) {
347
+ for (const entry of entriesForName) {
348
+ for (const targetName of relationTargets(entry.symbol.signature, "extends")) {
349
+ const targets = symbolsByName.get(targetName) ?? [];
350
+ for (const target of targets.slice(0, 3)) {
351
+ addEdge(edges, {
352
+ type: "inherits",
353
+ source: entry.id,
354
+ target: target.id,
355
+ confidence: targets.length === 1 ? "HEURISTIC" : "AMBIGUOUS",
356
+ evidence: "symbol signature extends clause",
357
+ metadata: { targetName, candidateCount: targets.length },
358
+ });
359
+ }
360
+ }
361
+ for (const targetName of relationTargets(entry.symbol.signature, "implements")) {
362
+ const targets = symbolsByName.get(targetName) ?? [];
363
+ for (const target of targets.slice(0, 3)) {
364
+ addEdge(edges, {
365
+ type: "implements",
366
+ source: entry.id,
367
+ target: target.id,
368
+ confidence: targets.length === 1 ? "HEURISTIC" : "AMBIGUOUS",
369
+ evidence: "symbol signature implements clause",
370
+ metadata: { targetName, candidateCount: targets.length },
371
+ });
372
+ }
373
+ }
374
+ }
375
+ }
376
+ let importCount = 0;
377
+ let callCount = 0;
378
+ let ambiguousCalls = 0;
379
+ let testCount = 0;
380
+ for (const file of files) {
381
+ const sourceFileId = fileNodeId(file.path);
382
+ for (const imp of db.getImportsFrom(file.id)) {
383
+ importCount++;
384
+ const targetFile = imp.target_file_id ? filesById.get(imp.target_file_id) : resolveRelativeImport(file.path, imp.target_path, filesByPath);
385
+ const targetId = targetFile ? fileNodeId(targetFile.path) : packageNodeId(imp.target_path);
386
+ if (!targetFile) {
387
+ addNode(nodes, {
388
+ id: targetId,
389
+ type: "package",
390
+ label: imp.target_path,
391
+ metadata: { unresolved: true },
392
+ });
393
+ }
394
+ addEdge(edges, {
395
+ type: "imports",
396
+ source: sourceFileId,
397
+ target: targetId,
398
+ confidence: targetFile ? "AST_EXTRACTED" : "HEURISTIC",
399
+ evidence: "import table",
400
+ metadata: {
401
+ importType: imp.import_type,
402
+ specifiers: parseImportedSymbols(imp.symbols_imported),
403
+ },
404
+ });
405
+ if (classifyFile(file) === "test" && targetFile && classifyFile(targetFile) !== "test") {
406
+ addEdge(edges, {
407
+ type: "tests",
408
+ source: sourceFileId,
409
+ target: targetId,
410
+ confidence: "AST_EXTRACTED",
411
+ evidence: "test imports source file",
412
+ });
413
+ testCount++;
414
+ }
415
+ }
416
+ for (const site of db.getCallSitesByFile(file.id)) {
417
+ const candidates = symbolsByName.get(site.callee) ?? [];
418
+ if (candidates.length === 0)
419
+ continue;
420
+ callCount++;
421
+ const selected = candidates.length === 1 ? candidates : candidates.slice(0, 5);
422
+ if (candidates.length > 1)
423
+ ambiguousCalls++;
424
+ for (const candidate of selected) {
425
+ addEdge(edges, {
426
+ type: candidates.length === 1 ? "calls" : "references",
427
+ source: sourceFileId,
428
+ target: candidate.id,
429
+ confidence: candidates.length === 1 ? "HEURISTIC" : "AMBIGUOUS",
430
+ evidence: "call site extraction",
431
+ metadata: {
432
+ callee: site.callee,
433
+ line: site.line,
434
+ context: site.context,
435
+ candidateCount: candidates.length,
436
+ },
437
+ });
438
+ }
439
+ }
440
+ }
441
+ const sourceFiles = files.filter((file) => classifyFile(file) !== "test");
442
+ const tests = files.filter((file) => classifyFile(file) === "test");
443
+ for (const test of tests) {
444
+ const base = testBase(test.path);
445
+ for (const source of sourceFiles) {
446
+ if (sourceBase(source.path) !== base)
447
+ continue;
448
+ addEdge(edges, {
449
+ type: "tests",
450
+ source: fileNodeId(test.path),
451
+ target: fileNodeId(source.path),
452
+ confidence: "HEURISTIC",
453
+ evidence: "test filename convention",
454
+ });
455
+ }
456
+ }
457
+ const ensureFileNode = (filePath) => {
458
+ const id = fileNodeId(filePath);
459
+ if (!nodes.has(id)) {
460
+ const parentId = ensureFolderChain(nodes, edges, projectId, filePath);
461
+ addNode(nodes, {
462
+ id,
463
+ type: classifyPath(filePath),
464
+ label: basename(filePath),
465
+ path: filePath,
466
+ metadata: { source: "scip" },
467
+ });
468
+ addEdge(edges, {
469
+ type: "contains",
470
+ source: parentId,
471
+ target: id,
472
+ confidence: "SCIP_RESOLVED",
473
+ evidence: "SCIP document path",
474
+ });
475
+ }
476
+ return id;
477
+ };
478
+ const scipSymbolIds = new Map();
479
+ const resolveScipSymbolId = (symbol, name, file, line) => {
480
+ const existing = scipSymbolIds.get(symbol);
481
+ if (existing)
482
+ return existing;
483
+ const candidates = symbolsByName.get(name) ?? [];
484
+ const matched = candidates.find((candidate) => {
485
+ if (file && candidate.file.path !== file)
486
+ return false;
487
+ if (line && Math.abs(candidate.symbol.line_start - line) > 1)
488
+ return false;
489
+ return true;
490
+ }) ?? candidates.find((candidate) => !file || candidate.file.path === file);
491
+ const id = matched?.id ?? scipSymbolNodeId(symbol);
492
+ scipSymbolIds.set(symbol, id);
493
+ return id;
494
+ };
495
+ const scipIndex = await loadScipIndex(rootDir);
496
+ if (scipIndex) {
497
+ for (const symbol of scipIndex.symbols) {
498
+ const id = resolveScipSymbolId(symbol.symbol, symbol.name, symbol.file, symbol.line);
499
+ if (!nodes.has(id)) {
500
+ addNode(nodes, {
501
+ id,
502
+ type: "symbol",
503
+ label: symbol.name,
504
+ path: symbol.file,
505
+ lineStart: symbol.line,
506
+ metadata: {
507
+ kind: symbol.kind,
508
+ signature: symbol.signature,
509
+ scipSymbol: symbol.symbol,
510
+ source: "scip",
511
+ },
512
+ });
513
+ }
514
+ if (symbol.file) {
515
+ addEdge(edges, {
516
+ type: "defines",
517
+ source: ensureFileNode(symbol.file),
518
+ target: id,
519
+ confidence: "SCIP_RESOLVED",
520
+ evidence: "SCIP symbol definition",
521
+ metadata: { symbol: symbol.symbol, line: symbol.line },
522
+ });
523
+ }
524
+ }
525
+ for (const occurrence of scipIndex.occurrences) {
526
+ const sourceId = ensureFileNode(occurrence.file);
527
+ const targetId = resolveScipSymbolId(occurrence.symbol, occurrence.name, occurrence.role === "definition" ? occurrence.file : undefined, occurrence.role === "definition" ? occurrence.line : undefined);
528
+ if (!nodes.has(targetId)) {
529
+ addNode(nodes, {
530
+ id: targetId,
531
+ type: "symbol",
532
+ label: occurrence.name,
533
+ path: occurrence.role === "definition" ? occurrence.file : undefined,
534
+ lineStart: occurrence.role === "definition" ? occurrence.line : undefined,
535
+ metadata: {
536
+ scipSymbol: occurrence.symbol,
537
+ source: "scip",
538
+ },
539
+ });
540
+ }
541
+ addEdge(edges, {
542
+ type: occurrence.role === "definition" ? "defines" : "references",
543
+ source: sourceId,
544
+ target: targetId,
545
+ confidence: "SCIP_RESOLVED",
546
+ evidence: occurrence.role === "definition" ? "SCIP definition occurrence" : "SCIP reference occurrence",
547
+ metadata: {
548
+ symbol: occurrence.symbol,
549
+ line: occurrence.line,
550
+ column: occurrence.column,
551
+ syntaxKind: occurrence.syntaxKind,
552
+ },
553
+ });
554
+ }
555
+ for (const symbol of scipIndex.symbols) {
556
+ const sourceId = resolveScipSymbolId(symbol.symbol, symbol.name, symbol.file, symbol.line);
557
+ for (const relationship of symbol.relationships) {
558
+ const targetName = scipIndex.symbols.find((candidate) => candidate.symbol === relationship.targetSymbol)?.name
559
+ ?? scipSymbolDisplayName(relationship.targetSymbol);
560
+ const targetId = resolveScipSymbolId(relationship.targetSymbol, targetName);
561
+ if (!nodes.has(targetId)) {
562
+ addNode(nodes, {
563
+ id: targetId,
564
+ type: "symbol",
565
+ label: targetName,
566
+ metadata: {
567
+ scipSymbol: relationship.targetSymbol,
568
+ source: "scip",
569
+ },
570
+ });
571
+ }
572
+ addEdge(edges, {
573
+ type: relationship.isImplementation ? "implements" : "references",
574
+ source: sourceId,
575
+ target: targetId,
576
+ confidence: "SCIP_RESOLVED",
577
+ evidence: "SCIP symbol relationship",
578
+ metadata: {
579
+ symbol: symbol.symbol,
580
+ targetSymbol: relationship.targetSymbol,
581
+ isReference: relationship.isReference,
582
+ isImplementation: relationship.isImplementation,
583
+ isTypeDefinition: relationship.isTypeDefinition,
584
+ isDefinition: relationship.isDefinition,
585
+ },
586
+ });
587
+ }
588
+ }
589
+ }
590
+ for (const pair of await collectCoChangePairs(rootDir, filesByPath)) {
591
+ addEdge(edges, {
592
+ type: "co_changes_with",
593
+ source: fileNodeId(pair.left),
594
+ target: fileNodeId(pair.right),
595
+ confidence: "HEURISTIC",
596
+ evidence: "recent git co-change history",
597
+ metadata: { commits: pair.count },
598
+ });
599
+ }
600
+ const graphNodes = [...nodes.values()].sort((a, b) => a.id.localeCompare(b.id));
601
+ const graphEdges = [...edges.values()].sort((a, b) => a.id.localeCompare(b.id));
602
+ const stats = {
603
+ nodes: graphNodes.length,
604
+ edges: graphEdges.length,
605
+ files: files.length,
606
+ symbols: symbolCount,
607
+ imports: importCount,
608
+ calls: callCount,
609
+ tests: graphEdges.filter((edge) => edge.type === "tests").length,
610
+ ambiguousCalls,
611
+ };
612
+ return {
613
+ version: 1,
614
+ generatedAt: new Date().toISOString(),
615
+ rootDir,
616
+ indexGeneration: db.getIndexGeneration(),
617
+ nodes: graphNodes,
618
+ edges: graphEdges,
619
+ stats,
620
+ };
621
+ }
622
+ export function formatGraphReport(graph) {
623
+ const byType = new Map();
624
+ const edgesByType = new Map();
625
+ for (const node of graph.nodes)
626
+ byType.set(node.type, (byType.get(node.type) ?? 0) + 1);
627
+ for (const edge of graph.edges)
628
+ edgesByType.set(edge.type, (edgesByType.get(edge.type) ?? 0) + 1);
629
+ const topImporters = graph.nodes
630
+ .filter((node) => ["file", "test"].includes(node.type) && node.path)
631
+ .map((node) => ({
632
+ node,
633
+ outbound: graph.edges.filter((edge) => edge.source === node.id && edge.type === "imports").length,
634
+ inbound: graph.edges.filter((edge) => edge.target === node.id && edge.type === "imports").length,
635
+ }))
636
+ .sort((a, b) => (b.inbound + b.outbound) - (a.inbound + a.outbound))
637
+ .slice(0, 12);
638
+ return [
639
+ "# ContextPro Graph Report",
640
+ "",
641
+ `Generated: ${graph.generatedAt}`,
642
+ `Index generation: ${graph.indexGeneration}`,
643
+ "",
644
+ "## Summary",
645
+ "",
646
+ `- Nodes: ${graph.stats.nodes}`,
647
+ `- Edges: ${graph.stats.edges}`,
648
+ `- Files: ${graph.stats.files}`,
649
+ `- Symbols: ${graph.stats.symbols}`,
650
+ `- Imports: ${graph.stats.imports}`,
651
+ `- Calls: ${graph.stats.calls}`,
652
+ `- Test edges: ${graph.stats.tests}`,
653
+ `- Ambiguous call references: ${graph.stats.ambiguousCalls}`,
654
+ "",
655
+ "## Node Types",
656
+ "",
657
+ ...[...byType.entries()].sort((a, b) => b[1] - a[1]).map(([type, count]) => `- ${type}: ${count}`),
658
+ "",
659
+ "## Edge Types",
660
+ "",
661
+ ...[...edgesByType.entries()].sort((a, b) => b[1] - a[1]).map(([type, count]) => `- ${type}: ${count}`),
662
+ "",
663
+ "## High-Connectivity Files",
664
+ "",
665
+ ...topImporters.map(({ node, inbound, outbound }) => `- ${node.path}: ${inbound} inbound imports, ${outbound} outbound imports`),
666
+ "",
667
+ "## Confidence Notes",
668
+ "",
669
+ "- `AST_EXTRACTED`: derived from parser/index tables.",
670
+ "- `HEURISTIC`: inferred from filenames, unresolved imports, or call-site names.",
671
+ "- `AMBIGUOUS`: call name matched multiple symbols; inspect before editing.",
672
+ "- `SCIP_RESOLVED`: exact facts imported from a project-provided SCIP JSON index.",
673
+ "- `LSP_RESOLVED`: exact references resolved by a local language service adapter.",
674
+ "",
675
+ ].join("\n");
676
+ }
677
+ function escapeHtml(value) {
678
+ return value
679
+ .replace(/&/g, "&amp;")
680
+ .replace(/</g, "&lt;")
681
+ .replace(/>/g, "&gt;")
682
+ .replace(/"/g, "&quot;");
683
+ }
684
+ export function formatGraphDashboard(graph) {
685
+ const nodeTypes = new Map();
686
+ const edgeTypes = new Map();
687
+ for (const node of graph.nodes)
688
+ nodeTypes.set(node.type, (nodeTypes.get(node.type) ?? 0) + 1);
689
+ for (const edge of graph.edges)
690
+ edgeTypes.set(edge.type, (edgeTypes.get(edge.type) ?? 0) + 1);
691
+ const topFiles = graph.nodes
692
+ .filter((node) => ["file", "test", "config", "document"].includes(node.type) && node.path)
693
+ .map((node) => ({
694
+ path: node.path ?? node.label,
695
+ type: node.type,
696
+ degree: graph.edges.filter((edge) => edge.source === node.id || edge.target === node.id).length,
697
+ }))
698
+ .sort((a, b) => b.degree - a.degree || a.path.localeCompare(b.path))
699
+ .slice(0, 30);
700
+ const rows = topFiles.map((file) => `<tr><td>${escapeHtml(file.path)}</td><td>${escapeHtml(file.type)}</td><td>${file.degree}</td></tr>`).join("\n");
701
+ const nodeCards = [...nodeTypes.entries()].sort((a, b) => b[1] - a[1])
702
+ .map(([type, count]) => `<li><span>${escapeHtml(type)}</span><strong>${count}</strong></li>`).join("\n");
703
+ const edgeCards = [...edgeTypes.entries()].sort((a, b) => b[1] - a[1])
704
+ .map(([type, count]) => `<li><span>${escapeHtml(type)}</span><strong>${count}</strong></li>`).join("\n");
705
+ return `<!doctype html>
706
+ <html lang="en">
707
+ <head>
708
+ <meta charset="utf-8">
709
+ <meta name="viewport" content="width=device-width, initial-scale=1">
710
+ <title>ContextPro Graph Dashboard</title>
711
+ <style>
712
+ body { margin: 0; font: 14px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #1f2937; background: #f8fafc; }
713
+ main { max-width: 1120px; margin: 0 auto; padding: 32px 20px 48px; }
714
+ h1, h2 { margin: 0; line-height: 1.15; }
715
+ h1 { font-size: 28px; }
716
+ h2 { font-size: 18px; margin-top: 30px; }
717
+ .meta { color: #64748b; margin-top: 8px; }
718
+ .stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin-top: 24px; }
719
+ .stat { background: white; border: 1px solid #e2e8f0; border-radius: 8px; padding: 14px; }
720
+ .stat span { color: #64748b; display: block; font-size: 12px; }
721
+ .stat strong { display: block; font-size: 24px; margin-top: 4px; }
722
+ .lists { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; margin-top: 12px; }
723
+ ul { list-style: none; padding: 0; margin: 0; background: white; border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden; }
724
+ li { display: flex; justify-content: space-between; gap: 16px; padding: 10px 12px; border-bottom: 1px solid #e2e8f0; }
725
+ li:last-child { border-bottom: 0; }
726
+ table { width: 100%; border-collapse: collapse; margin-top: 12px; background: white; border: 1px solid #e2e8f0; border-radius: 8px; overflow: hidden; }
727
+ th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #e2e8f0; }
728
+ th { color: #475569; background: #f1f5f9; font-size: 12px; text-transform: uppercase; }
729
+ tr:last-child td { border-bottom: 0; }
730
+ </style>
731
+ </head>
732
+ <body>
733
+ <main>
734
+ <h1>ContextPro Graph Dashboard</h1>
735
+ <div class="meta">Generated ${escapeHtml(graph.generatedAt)} | Index generation ${graph.indexGeneration}</div>
736
+ <section class="stats">
737
+ <div class="stat"><span>Nodes</span><strong>${graph.stats.nodes}</strong></div>
738
+ <div class="stat"><span>Edges</span><strong>${graph.stats.edges}</strong></div>
739
+ <div class="stat"><span>Files</span><strong>${graph.stats.files}</strong></div>
740
+ <div class="stat"><span>Symbols</span><strong>${graph.stats.symbols}</strong></div>
741
+ <div class="stat"><span>Imports</span><strong>${graph.stats.imports}</strong></div>
742
+ <div class="stat"><span>Ambiguous Calls</span><strong>${graph.stats.ambiguousCalls}</strong></div>
743
+ </section>
744
+ <section class="lists">
745
+ <div><h2>Node Types</h2><ul>${nodeCards}</ul></div>
746
+ <div><h2>Edge Types</h2><ul>${edgeCards}</ul></div>
747
+ </section>
748
+ <h2>High-Connectivity Files</h2>
749
+ <table>
750
+ <thead><tr><th>Path</th><th>Type</th><th>Degree</th></tr></thead>
751
+ <tbody>${rows}</tbody>
752
+ </table>
753
+ </main>
754
+ </body>
755
+ </html>
756
+ `;
757
+ }
758
+ export async function writeProjectGraphArtifacts(rootDir) {
759
+ const graph = await buildProjectGraph(rootDir);
760
+ const graphPath = resolveProjectPath(rootDir, ".contextpro/graph.json", "graphPath");
761
+ const reportPath = resolveProjectPath(rootDir, ".contextpro/GRAPH_REPORT.md", "reportPath");
762
+ const dashboardPath = resolveProjectPath(rootDir, ".contextpro/graph-dashboard.html", "dashboardPath");
763
+ await mkdir(dirname(graphPath), { recursive: true });
764
+ // graph.json is read by impact_delta — write it atomically so a crash can't leave a torn file.
765
+ await writeFileAtomic(graphPath, JSON.stringify(graph, null, 2) + "\n");
766
+ await writeFileAtomic(reportPath, formatGraphReport(graph));
767
+ await writeFileAtomic(dashboardPath, formatGraphDashboard(graph));
768
+ return { graph, graphPath, reportPath, dashboardPath };
769
+ }
770
+ function graphSummary(graph) {
771
+ return { generatedAt: graph.generatedAt, indexGeneration: graph.indexGeneration, stats: graph.stats };
772
+ }
773
+ export async function queryProjectGraph(rootDir, input) {
774
+ const graph = await buildProjectGraph(rootDir);
775
+ const summary = graphSummary(graph);
776
+ const limit = Math.max(1, Math.min(input.limit ?? 50, 200));
777
+ const kind = input.kind ?? "summary";
778
+ if (kind === "summary") {
779
+ return { graph: summary, nodes: graph.nodes.slice(0, limit), edges: graph.edges.slice(0, limit) };
780
+ }
781
+ if (kind === "path") {
782
+ const path = findWeightedShortestPath(graph, input.source ?? "", input.target ?? "", Math.max(1, Math.min(input.maxHops ?? 8, 20)));
783
+ return { graph: summary, ...path };
784
+ }
785
+ if (kind === "hotspots") {
786
+ const rankings = rankGraphHotspots(graph, limit);
787
+ const byId = new Map(graph.nodes.map((node) => [node.id, node]));
788
+ const nodes = rankings.map((ranking) => {
789
+ const node = byId.get(ranking.nodeId);
790
+ return { ...node, metadata: { ...node.metadata, centrality: ranking } };
791
+ });
792
+ const nodeIds = new Set(rankings.map((ranking) => ranking.nodeId));
793
+ const edges = graph.edges
794
+ .filter((edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target) && edge.type !== "contains")
795
+ .slice(0, limit);
796
+ return { graph: summary, nodes, edges, analysis: { kind: "hotspots", rankings } };
797
+ }
798
+ if (kind === "communities") {
799
+ const communities = detectGraphCommunities(graph, Math.min(limit, 25));
800
+ const selectedPaths = new Set(communities.flatMap((community) => community.files));
801
+ const nodes = graph.nodes
802
+ .filter((node) => node.path && selectedPaths.has(node.path) && ["file", "test", "config", "document"].includes(node.type))
803
+ .slice(0, limit);
804
+ const nodeIds = new Set(nodes.map((node) => node.id));
805
+ const edges = graph.edges
806
+ .filter((edge) => nodeIds.has(edge.source) && nodeIds.has(edge.target) && edge.type !== "contains")
807
+ .slice(0, limit);
808
+ return { graph: summary, nodes, edges, analysis: { kind: "communities", communities } };
809
+ }
810
+ const startNodes = graph.nodes.filter((node) => {
811
+ if (kind === "file" || kind === "impact") {
812
+ return input.file ? node.path === input.file : false;
813
+ }
814
+ return input.symbol ? node.type === "symbol" && node.label === input.symbol : false;
815
+ });
816
+ const startIds = new Set(startNodes.map((node) => node.id));
817
+ if (kind === "impact") {
818
+ // Impact: BFS over INCOMING dependencies — files that would need attention if the start file changes.
819
+ // Edge selection: an edge from S→T contributes S to the dependent frontier when:
820
+ // - T is in the current frontier (a file) AND edge.type ∈ {imports, tests}
821
+ // - T is a symbol DEFINED by a file in the current frontier AND edge.type ∈ {calls, references, tests}
822
+ // Limit is a SINGLE budget for edges in the output. Nodes are derived from the bounded edge set.
823
+ const MAX_HOPS = 3;
824
+ const fileFrontier = new Set(startIds);
825
+ const symbolFrontier = new Set();
826
+ const collectedEdges = [];
827
+ const edgeBudget = limit;
828
+ for (let hop = 0; hop < MAX_HOPS && collectedEdges.length < edgeBudget; hop++) {
829
+ // For each new file in the frontier, collect its defined symbols once.
830
+ const newSymbols = new Set();
831
+ for (const edge of graph.edges) {
832
+ if (!fileFrontier.has(edge.source))
833
+ continue;
834
+ if (edge.type !== "defines")
835
+ continue;
836
+ if (symbolFrontier.has(edge.target))
837
+ continue;
838
+ symbolFrontier.add(edge.target);
839
+ newSymbols.add(edge.target);
840
+ }
841
+ const newDependents = new Set();
842
+ for (const edge of graph.edges) {
843
+ if (collectedEdges.length >= edgeBudget)
844
+ break;
845
+ const targetsFile = fileFrontier.has(edge.target) && (edge.type === "imports" || edge.type === "tests");
846
+ const targetsSymbol = symbolFrontier.has(edge.target) && (edge.type === "calls" || edge.type === "references" || edge.type === "tests");
847
+ if (!targetsFile && !targetsSymbol)
848
+ continue;
849
+ if (fileFrontier.has(edge.source))
850
+ continue;
851
+ collectedEdges.push(edge);
852
+ newDependents.add(edge.source);
853
+ }
854
+ if (newDependents.size === 0)
855
+ break;
856
+ for (const id of newDependents)
857
+ fileFrontier.add(id);
858
+ }
859
+ const nodeIds = new Set([...fileFrontier, ...symbolFrontier]);
860
+ const nodes = graph.nodes.filter((node) => nodeIds.has(node.id));
861
+ return { graph: summary, nodes, edges: collectedEdges };
862
+ }
863
+ const edges = graph.edges
864
+ .filter((edge) => startIds.has(edge.source) || startIds.has(edge.target))
865
+ .slice(0, limit);
866
+ const nodeIds = new Set([...startIds]);
867
+ for (const edge of edges) {
868
+ nodeIds.add(edge.source);
869
+ nodeIds.add(edge.target);
870
+ }
871
+ const nodes = graph.nodes.filter((node) => nodeIds.has(node.id)).slice(0, limit);
872
+ return { graph: summary, nodes, edges };
873
+ }
874
+ //# sourceMappingURL=project-graph.js.map