kirograph 0.16.1 → 0.19.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 (365) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +103 -1605
  3. package/dist/architecture/layers/dart.js +112 -0
  4. package/dist/architecture/layers/dart.js.map +7 -0
  5. package/dist/architecture/layers/index.js +3 -1
  6. package/dist/architecture/layers/index.js.map +2 -2
  7. package/dist/bin/banner.js +74 -6
  8. package/dist/bin/banner.js.map +2 -2
  9. package/dist/bin/commands/affected.js +40 -5
  10. package/dist/bin/commands/affected.js.map +2 -2
  11. package/dist/bin/commands/attack-surface.js +157 -0
  12. package/dist/bin/commands/attack-surface.js.map +7 -0
  13. package/dist/bin/commands/benchmark.js +206 -0
  14. package/dist/bin/commands/benchmark.js.map +7 -0
  15. package/dist/bin/commands/budget.js +70 -0
  16. package/dist/bin/commands/budget.js.map +7 -0
  17. package/dist/bin/commands/communities.js +77 -0
  18. package/dist/bin/commands/communities.js.map +7 -0
  19. package/dist/bin/commands/data.js +665 -0
  20. package/dist/bin/commands/data.js.map +7 -0
  21. package/dist/bin/commands/dep-confusion.js +119 -0
  22. package/dist/bin/commands/dep-confusion.js.map +7 -0
  23. package/dist/bin/commands/export.js +304 -10
  24. package/dist/bin/commands/export.js.map +2 -2
  25. package/dist/bin/commands/flows.js +97 -0
  26. package/dist/bin/commands/flows.js.map +7 -0
  27. package/dist/bin/commands/help.js +386 -100
  28. package/dist/bin/commands/help.js.map +2 -2
  29. package/dist/bin/commands/install.js +90 -8
  30. package/dist/bin/commands/install.js.map +2 -2
  31. package/dist/bin/commands/licenses.js +201 -0
  32. package/dist/bin/commands/licenses.js.map +7 -0
  33. package/dist/bin/commands/reachability.js +160 -0
  34. package/dist/bin/commands/reachability.js.map +7 -0
  35. package/dist/bin/commands/read.js +100 -0
  36. package/dist/bin/commands/read.js.map +7 -0
  37. package/dist/bin/commands/refactor.js +116 -0
  38. package/dist/bin/commands/refactor.js.map +7 -0
  39. package/dist/bin/commands/remediation.js +133 -0
  40. package/dist/bin/commands/remediation.js.map +7 -0
  41. package/dist/bin/commands/sbom.js +76 -0
  42. package/dist/bin/commands/sbom.js.map +7 -0
  43. package/dist/bin/commands/security-ci-report.js +267 -0
  44. package/dist/bin/commands/security-ci-report.js.map +7 -0
  45. package/dist/bin/commands/security-export.js +1349 -0
  46. package/dist/bin/commands/security-export.js.map +7 -0
  47. package/dist/bin/commands/security-flows.js +126 -0
  48. package/dist/bin/commands/security-flows.js.map +7 -0
  49. package/dist/bin/commands/security-secrets.js +170 -0
  50. package/dist/bin/commands/security-secrets.js.map +7 -0
  51. package/dist/bin/commands/security.js +193 -0
  52. package/dist/bin/commands/security.js.map +7 -0
  53. package/dist/bin/commands/staleness.js +144 -0
  54. package/dist/bin/commands/staleness.js.map +7 -0
  55. package/dist/bin/commands/status.js +102 -2
  56. package/dist/bin/commands/status.js.map +2 -2
  57. package/dist/bin/commands/supply-chain.js +138 -0
  58. package/dist/bin/commands/supply-chain.js.map +7 -0
  59. package/dist/bin/commands/uninit.js +109 -60
  60. package/dist/bin/commands/uninit.js.map +2 -2
  61. package/dist/bin/commands/vex.js +76 -0
  62. package/dist/bin/commands/vex.js.map +7 -0
  63. package/dist/bin/commands/vuln-suppress.js +95 -0
  64. package/dist/bin/commands/vuln-suppress.js.map +7 -0
  65. package/dist/bin/commands/vulns.js +382 -0
  66. package/dist/bin/commands/vulns.js.map +7 -0
  67. package/dist/bin/installer/auto-detect.js +125 -0
  68. package/dist/bin/installer/auto-detect.js.map +7 -0
  69. package/dist/bin/installer/cli-agent.js +28 -5
  70. package/dist/bin/installer/cli-agent.js.map +2 -2
  71. package/dist/bin/installer/common.js +47 -0
  72. package/dist/bin/installer/common.js.map +2 -2
  73. package/dist/bin/installer/config-prompt.js +39 -1
  74. package/dist/bin/installer/config-prompt.js.map +2 -2
  75. package/dist/bin/installer/detect.js +309 -0
  76. package/dist/bin/installer/detect.js.map +7 -0
  77. package/dist/bin/installer/index.js +36 -1
  78. package/dist/bin/installer/index.js.map +2 -2
  79. package/dist/bin/installer/instructions.js +195 -3
  80. package/dist/bin/installer/instructions.js.map +2 -2
  81. package/dist/bin/installer/steering.js +440 -0
  82. package/dist/bin/installer/steering.js.map +2 -2
  83. package/dist/bin/installer/targets/aider.js +3 -3
  84. package/dist/bin/installer/targets/aider.js.map +2 -2
  85. package/dist/bin/installer/targets/amp.js +3 -3
  86. package/dist/bin/installer/targets/amp.js.map +2 -2
  87. package/dist/bin/installer/targets/antigravity.js +35 -6
  88. package/dist/bin/installer/targets/antigravity.js.map +2 -2
  89. package/dist/bin/installer/targets/augment.js +3 -3
  90. package/dist/bin/installer/targets/augment.js.map +2 -2
  91. package/dist/bin/installer/targets/claude.js +49 -5
  92. package/dist/bin/installer/targets/claude.js.map +2 -2
  93. package/dist/bin/installer/targets/cline.js +32 -6
  94. package/dist/bin/installer/targets/cline.js.map +2 -2
  95. package/dist/bin/installer/targets/codex.js +64 -12
  96. package/dist/bin/installer/targets/codex.js.map +2 -2
  97. package/dist/bin/installer/targets/continue.js +2 -2
  98. package/dist/bin/installer/targets/continue.js.map +2 -2
  99. package/dist/bin/installer/targets/copilot-cli.js +101 -0
  100. package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
  101. package/dist/bin/installer/targets/copilot.js +31 -5
  102. package/dist/bin/installer/targets/copilot.js.map +2 -2
  103. package/dist/bin/installer/targets/cursor.js +4 -4
  104. package/dist/bin/installer/targets/cursor.js.map +2 -2
  105. package/dist/bin/installer/targets/devin.js +2 -2
  106. package/dist/bin/installer/targets/devin.js.map +2 -2
  107. package/dist/bin/installer/targets/gemini-cli.js +2 -2
  108. package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
  109. package/dist/bin/installer/targets/generic.js +2 -14
  110. package/dist/bin/installer/targets/generic.js.map +2 -2
  111. package/dist/bin/installer/targets/goose.js +3 -3
  112. package/dist/bin/installer/targets/goose.js.map +2 -2
  113. package/dist/bin/installer/targets/index.js +250 -0
  114. package/dist/bin/installer/targets/index.js.map +2 -2
  115. package/dist/bin/installer/targets/junie.js +2 -2
  116. package/dist/bin/installer/targets/junie.js.map +2 -2
  117. package/dist/bin/installer/targets/kilo.js +2 -2
  118. package/dist/bin/installer/targets/kilo.js.map +2 -2
  119. package/dist/bin/installer/targets/kiro.js +3 -3
  120. package/dist/bin/installer/targets/kiro.js.map +2 -2
  121. package/dist/bin/installer/targets/opencode.js +2 -2
  122. package/dist/bin/installer/targets/opencode.js.map +2 -2
  123. package/dist/bin/installer/targets/openhands.js +3 -3
  124. package/dist/bin/installer/targets/openhands.js.map +2 -2
  125. package/dist/bin/installer/targets/qoder.js +91 -0
  126. package/dist/bin/installer/targets/qoder.js.map +7 -0
  127. package/dist/bin/installer/targets/qwen.js +96 -0
  128. package/dist/bin/installer/targets/qwen.js.map +7 -0
  129. package/dist/bin/installer/targets/replit.js +3 -3
  130. package/dist/bin/installer/targets/replit.js.map +2 -2
  131. package/dist/bin/installer/targets/roo.js +2 -2
  132. package/dist/bin/installer/targets/roo.js.map +2 -2
  133. package/dist/bin/installer/targets/tabnine.js +3 -3
  134. package/dist/bin/installer/targets/tabnine.js.map +2 -2
  135. package/dist/bin/installer/targets/trae.js +5 -5
  136. package/dist/bin/installer/targets/trae.js.map +2 -2
  137. package/dist/bin/installer/targets/warp.js +2 -2
  138. package/dist/bin/installer/targets/warp.js.map +2 -2
  139. package/dist/bin/installer/targets/windsurf.js +35 -6
  140. package/dist/bin/installer/targets/windsurf.js.map +2 -2
  141. package/dist/bin/kirograph.js +74 -6
  142. package/dist/bin/kirograph.js.map +3 -3
  143. package/dist/bin/progress.js +30 -0
  144. package/dist/bin/progress.js.map +2 -2
  145. package/dist/compression/naive-cost.js +25 -0
  146. package/dist/compression/naive-cost.js.map +2 -2
  147. package/dist/compression/tracker.js +91 -2
  148. package/dist/compression/tracker.js.map +2 -2
  149. package/dist/compression/types.js.map +1 -1
  150. package/dist/config.js +126 -3
  151. package/dist/config.js.map +2 -2
  152. package/dist/core/pipeline.js +92 -4
  153. package/dist/core/pipeline.js.map +2 -2
  154. package/dist/data/filters.js +105 -0
  155. package/dist/data/filters.js.map +7 -0
  156. package/dist/data/indexer.js +225 -0
  157. package/dist/data/indexer.js.map +7 -0
  158. package/dist/data/linker.js +150 -0
  159. package/dist/data/linker.js.map +7 -0
  160. package/dist/data/lint.js +109 -0
  161. package/dist/data/lint.js.map +7 -0
  162. package/dist/data/parsers/csv.js +132 -0
  163. package/dist/data/parsers/csv.js.map +7 -0
  164. package/dist/data/parsers/excel.js +88 -0
  165. package/dist/data/parsers/excel.js.map +7 -0
  166. package/dist/data/parsers/index.js +79 -0
  167. package/dist/data/parsers/index.js.map +7 -0
  168. package/dist/data/parsers/json-array.js +89 -0
  169. package/dist/data/parsers/json-array.js.map +7 -0
  170. package/dist/data/parsers/jsonl.js +84 -0
  171. package/dist/data/parsers/jsonl.js.map +7 -0
  172. package/dist/data/parsers/parquet.js +95 -0
  173. package/dist/data/parsers/parquet.js.map +7 -0
  174. package/dist/data/profiler.js +182 -0
  175. package/dist/data/profiler.js.map +7 -0
  176. package/dist/data/queries.js +512 -0
  177. package/dist/data/queries.js.map +7 -0
  178. package/dist/data/types.js +17 -0
  179. package/dist/data/types.js.map +7 -0
  180. package/dist/db/data-schema.sql +61 -0
  181. package/dist/db/database.js +67 -5
  182. package/dist/db/database.js.map +2 -2
  183. package/dist/db/memory-schema.sql +5 -1
  184. package/dist/db/schema.sql +3 -1
  185. package/dist/db/security-schema.sql +72 -0
  186. package/dist/extraction/extractor.js +81 -0
  187. package/dist/extraction/extractor.js.map +2 -2
  188. package/dist/extraction/grammars.js +32 -8
  189. package/dist/extraction/grammars.js.map +2 -2
  190. package/dist/extraction/languages.js +43 -1
  191. package/dist/extraction/languages.js.map +2 -2
  192. package/dist/extraction/notebook.js +300 -0
  193. package/dist/extraction/notebook.js.map +7 -0
  194. package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
  195. package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
  196. package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
  197. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  198. package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
  199. package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
  200. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  201. package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
  202. package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
  203. package/dist/frameworks/flutter.js +130 -0
  204. package/dist/frameworks/flutter.js.map +7 -0
  205. package/dist/frameworks/index.js +7 -1
  206. package/dist/frameworks/index.js.map +3 -3
  207. package/dist/graph/communities.js +317 -0
  208. package/dist/graph/communities.js.map +7 -0
  209. package/dist/graph/flows.js +138 -0
  210. package/dist/graph/flows.js.map +7 -0
  211. package/dist/graph/refactor.js +155 -0
  212. package/dist/graph/refactor.js.map +7 -0
  213. package/dist/index.js +1 -1
  214. package/dist/index.js.map +2 -2
  215. package/dist/mcp/cache.js +172 -0
  216. package/dist/mcp/cache.js.map +7 -0
  217. package/dist/mcp/read-modes.js +295 -0
  218. package/dist/mcp/read-modes.js.map +7 -0
  219. package/dist/mcp/server.js +2 -1
  220. package/dist/mcp/server.js.map +2 -2
  221. package/dist/mcp/tool-names.js +29 -1
  222. package/dist/mcp/tool-names.js.map +2 -2
  223. package/dist/mcp/tools.js +1588 -6
  224. package/dist/mcp/tools.js.map +3 -3
  225. package/dist/memory/database.js +32 -2
  226. package/dist/memory/database.js.map +2 -2
  227. package/dist/memory/types.js.map +1 -1
  228. package/dist/resolution/bridges/android-rn.js +298 -0
  229. package/dist/resolution/bridges/android-rn.js.map +7 -0
  230. package/dist/resolution/bridges/expo-modules.js +155 -0
  231. package/dist/resolution/bridges/expo-modules.js.map +7 -0
  232. package/dist/resolution/bridges/flutter-channel.js +385 -0
  233. package/dist/resolution/bridges/flutter-channel.js.map +7 -0
  234. package/dist/resolution/bridges/index.js +80 -0
  235. package/dist/resolution/bridges/index.js.map +7 -0
  236. package/dist/resolution/bridges/native-events.js +188 -0
  237. package/dist/resolution/bridges/native-events.js.map +7 -0
  238. package/dist/resolution/bridges/native-views.js +244 -0
  239. package/dist/resolution/bridges/native-views.js.map +7 -0
  240. package/dist/resolution/bridges/react-native.js +161 -0
  241. package/dist/resolution/bridges/react-native.js.map +7 -0
  242. package/dist/resolution/bridges/swift-objc.js +227 -0
  243. package/dist/resolution/bridges/swift-objc.js.map +7 -0
  244. package/dist/resolution/bridges/turbomodules.js +216 -0
  245. package/dist/resolution/bridges/turbomodules.js.map +7 -0
  246. package/dist/resolution/index.js +61 -2
  247. package/dist/resolution/index.js.map +2 -2
  248. package/dist/security/attack-surface.js +164 -0
  249. package/dist/security/attack-surface.js.map +7 -0
  250. package/dist/security/context-warnings.js +123 -0
  251. package/dist/security/context-warnings.js.map +7 -0
  252. package/dist/security/context-warnings.test.js +300 -0
  253. package/dist/security/context-warnings.test.js.map +7 -0
  254. package/dist/security/data-flows.js +228 -0
  255. package/dist/security/data-flows.js.map +7 -0
  256. package/dist/security/dep-confusion.js +255 -0
  257. package/dist/security/dep-confusion.js.map +7 -0
  258. package/dist/security/errors.js +51 -0
  259. package/dist/security/errors.js.map +7 -0
  260. package/dist/security/export/fix-suggestions.js +58 -0
  261. package/dist/security/export/fix-suggestions.js.map +7 -0
  262. package/dist/security/export/fix-suggestions.test.js +74 -0
  263. package/dist/security/export/fix-suggestions.test.js.map +7 -0
  264. package/dist/security/export/sbom.js +230 -0
  265. package/dist/security/export/sbom.js.map +7 -0
  266. package/dist/security/export/sbom.test.js +288 -0
  267. package/dist/security/export/sbom.test.js.map +7 -0
  268. package/dist/security/export/serialization.js +142 -0
  269. package/dist/security/export/serialization.js.map +7 -0
  270. package/dist/security/export/serialization.test.js +310 -0
  271. package/dist/security/export/serialization.test.js.map +7 -0
  272. package/dist/security/export/vex.js +220 -0
  273. package/dist/security/export/vex.js.map +7 -0
  274. package/dist/security/export/vex.test.js +278 -0
  275. package/dist/security/export/vex.test.js.map +7 -0
  276. package/dist/security/index.js +67 -0
  277. package/dist/security/index.js.map +7 -0
  278. package/dist/security/integrator-transitives.test.js +359 -0
  279. package/dist/security/integrator-transitives.test.js.map +7 -0
  280. package/dist/security/integrator.js +491 -0
  281. package/dist/security/integrator.js.map +7 -0
  282. package/dist/security/integrator.test.js +237 -0
  283. package/dist/security/integrator.test.js.map +7 -0
  284. package/dist/security/license.js +70 -0
  285. package/dist/security/license.js.map +7 -0
  286. package/dist/security/manifest/adapter.js +243 -0
  287. package/dist/security/manifest/adapter.js.map +7 -0
  288. package/dist/security/manifest/adapter.test.js +272 -0
  289. package/dist/security/manifest/adapter.test.js.map +7 -0
  290. package/dist/security/manifest/parser.js +376 -0
  291. package/dist/security/manifest/parser.js.map +7 -0
  292. package/dist/security/manifest/parser.test.js +110 -0
  293. package/dist/security/manifest/parser.test.js.map +7 -0
  294. package/dist/security/manifest/plugins/cargo.js +233 -0
  295. package/dist/security/manifest/plugins/cargo.js.map +7 -0
  296. package/dist/security/manifest/plugins/cargo.test.js +304 -0
  297. package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
  298. package/dist/security/manifest/plugins/composer.js +152 -0
  299. package/dist/security/manifest/plugins/composer.js.map +7 -0
  300. package/dist/security/manifest/plugins/go.js +146 -0
  301. package/dist/security/manifest/plugins/go.js.map +7 -0
  302. package/dist/security/manifest/plugins/go.test.js +341 -0
  303. package/dist/security/manifest/plugins/go.test.js.map +7 -0
  304. package/dist/security/manifest/plugins/gradle.js +159 -0
  305. package/dist/security/manifest/plugins/gradle.js.map +7 -0
  306. package/dist/security/manifest/plugins/hex.js +159 -0
  307. package/dist/security/manifest/plugins/hex.js.map +7 -0
  308. package/dist/security/manifest/plugins/maven.js +128 -0
  309. package/dist/security/manifest/plugins/maven.js.map +7 -0
  310. package/dist/security/manifest/plugins/maven.test.js +389 -0
  311. package/dist/security/manifest/plugins/maven.test.js.map +7 -0
  312. package/dist/security/manifest/plugins/npm.js +284 -0
  313. package/dist/security/manifest/plugins/npm.js.map +7 -0
  314. package/dist/security/manifest/plugins/npm.test.js +298 -0
  315. package/dist/security/manifest/plugins/npm.test.js.map +7 -0
  316. package/dist/security/manifest/plugins/nuget.js +186 -0
  317. package/dist/security/manifest/plugins/nuget.js.map +7 -0
  318. package/dist/security/manifest/plugins/pip.js +123 -0
  319. package/dist/security/manifest/plugins/pip.js.map +7 -0
  320. package/dist/security/manifest/plugins/pip.test.js +208 -0
  321. package/dist/security/manifest/plugins/pip.test.js.map +7 -0
  322. package/dist/security/manifest/plugins/pubspec.js +212 -0
  323. package/dist/security/manifest/plugins/pubspec.js.map +7 -0
  324. package/dist/security/manifest/plugins/pyproject.js +261 -0
  325. package/dist/security/manifest/plugins/pyproject.js.map +7 -0
  326. package/dist/security/manifest/plugins/rubygems.js +185 -0
  327. package/dist/security/manifest/plugins/rubygems.js.map +7 -0
  328. package/dist/security/manifest/plugins/swift.js +200 -0
  329. package/dist/security/manifest/plugins/swift.js.map +7 -0
  330. package/dist/security/owasp.js +104 -0
  331. package/dist/security/owasp.js.map +7 -0
  332. package/dist/security/pipeline.js +125 -0
  333. package/dist/security/pipeline.js.map +7 -0
  334. package/dist/security/reachability.js +276 -0
  335. package/dist/security/reachability.js.map +7 -0
  336. package/dist/security/reachability.test.js +394 -0
  337. package/dist/security/reachability.test.js.map +7 -0
  338. package/dist/security/remediation.js +126 -0
  339. package/dist/security/remediation.js.map +7 -0
  340. package/dist/security/secrets.js +176 -0
  341. package/dist/security/secrets.js.map +7 -0
  342. package/dist/security/staleness.js +231 -0
  343. package/dist/security/staleness.js.map +7 -0
  344. package/dist/security/supply-chain.js +301 -0
  345. package/dist/security/supply-chain.js.map +7 -0
  346. package/dist/security/suppressions.js +106 -0
  347. package/dist/security/suppressions.js.map +7 -0
  348. package/dist/security/types.js +17 -0
  349. package/dist/security/types.js.map +7 -0
  350. package/dist/security/vuln/client.js +355 -0
  351. package/dist/security/vuln/client.js.map +7 -0
  352. package/dist/security/vuln/client.test.js +288 -0
  353. package/dist/security/vuln/client.test.js.map +7 -0
  354. package/dist/security/vuln/epss-client.js +95 -0
  355. package/dist/security/vuln/epss-client.js.map +7 -0
  356. package/dist/security/vuln/index.js +29 -0
  357. package/dist/security/vuln/index.js.map +7 -0
  358. package/dist/security/vuln/osv-adapter.js +321 -0
  359. package/dist/security/vuln/osv-adapter.js.map +7 -0
  360. package/dist/security/vuln/osv-adapter.test.js +391 -0
  361. package/dist/security/vuln/osv-adapter.test.js.map +7 -0
  362. package/dist/security/vuln/types.js +17 -0
  363. package/dist/security/vuln/types.js.map +7 -0
  364. package/dist/types.js.map +2 -2
  365. package/package.json +5 -2
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/resolution/bridges/turbomodules.ts"],
4
+ "sourcesContent": ["/**\n * React Native TurboModules Bridge\n *\n * Synthesizes edges between TypeScript TurboModule spec interfaces and their\n * native implementations. TurboModules use codegen specs (Native*.ts files)\n * as the source of truth for the JS \u2194 Native contract.\n */\n\nimport type { Node } from '../../types';\nimport type { ResolutionContext } from '../../frameworks/types';\nimport type { BridgeResolver, SynthesizedEdge } from './index';\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ninterface TurboModuleSpec {\n moduleName: string;\n methods: string[];\n specFilePath: string;\n specNodeId?: string;\n}\n\ninterface NativeImpl {\n moduleName: string;\n methods: Map<string, string>; // methodName \u2192 nodeId\n filePath: string;\n}\n\n/**\n * Find TurboModule spec files (Native*.ts) and extract their interfaces.\n */\nfunction findTurboModuleSpecs(context: ResolutionContext): TurboModuleSpec[] {\n const specs: TurboModuleSpec[] = [];\n const files = context.getAllFiles();\n\n for (const f of files) {\n // TurboModule specs follow the naming convention Native*.ts\n const fileName = f.split('/').pop() ?? '';\n if (!fileName.match(/^Native\\w+\\.(ts|tsx|js)$/)) continue;\n\n const content = context.readFile(f);\n if (!content) continue;\n\n // Check for TurboModule interface pattern\n const specMatch = content.match(\n /export\\s+interface\\s+Spec\\s+extends\\s+TurboModule\\s*\\{([^}]*)\\}/s\n );\n if (!specMatch) continue;\n\n // Extract module name from filename: NativeFoo.ts \u2192 Foo\n const moduleName = fileName.replace(/^Native/, '').replace(/\\.(ts|tsx|js)$/, '');\n\n // Extract method names from the interface body\n const methods: string[] = [];\n const methodRegex = /(\\w+)\\s*\\(/g;\n let match: RegExpExecArray | null;\n while ((match = methodRegex.exec(specMatch[1])) !== null) {\n methods.push(match[1]);\n }\n\n // Find the interface node\n const nodes = context.getNodesInFile(f);\n const specNode = nodes.find(\n n => n.kind === 'interface' && n.name === 'Spec'\n );\n\n specs.push({\n moduleName,\n methods,\n specFilePath: f,\n specNodeId: specNode?.id,\n });\n }\n\n return specs;\n}\n\n/**\n * Find native implementations that match TurboModule specs.\n */\nfunction findNativeImpls(context: ResolutionContext, moduleNames: Set<string>): NativeImpl[] {\n const impls: NativeImpl[] = [];\n const files = context.getAllFiles();\n\n for (const f of files) {\n if (!f.endsWith('.m') && !f.endsWith('.mm') && !f.endsWith('.swift') &&\n !f.endsWith('.java') && !f.endsWith('.kt')) {\n continue;\n }\n\n const content = context.readFile(f);\n if (!content) continue;\n\n // Try to identify which module this file implements\n let moduleName: string | null = null;\n\n // ObjC: @implementation RCT<ModuleName> or class name matching\n if (f.endsWith('.m') || f.endsWith('.mm')) {\n const implMatch = content.match(/@implementation\\s+(\\w+)/);\n if (implMatch) {\n const className = implMatch[1];\n // Try stripping common prefixes\n for (const name of moduleNames) {\n if (className === name || className === `RCT${name}` ||\n className === `${name}Module` || className === `RCT${name}Module`) {\n moduleName = name;\n break;\n }\n }\n }\n }\n\n // Swift: class that conforms to module name\n if (f.endsWith('.swift')) {\n const classMatch = content.match(/class\\s+(\\w+)\\s*:/);\n if (classMatch) {\n const className = classMatch[1];\n for (const name of moduleNames) {\n if (className === name || className === `${name}Module`) {\n moduleName = name;\n break;\n }\n }\n }\n }\n\n // Java/Kotlin: class extending ReactContextBaseJavaModule or TurboModule\n if (f.endsWith('.java') || f.endsWith('.kt')) {\n const classMatch = content.match(/class\\s+(\\w+)\\s+(?:extends|:)\\s+\\w*(?:TurboModule|ReactContextBaseJavaModule)/);\n if (classMatch) {\n const className = classMatch[1];\n for (const name of moduleNames) {\n if (className === name || className === `${name}Module`) {\n moduleName = name;\n break;\n }\n }\n }\n\n // Also check getName() return value\n const getNameMatch = content.match(/getName\\s*\\(\\s*\\)\\s*(?::\\s*String\\s*)?\\{[^}]*return\\s*\"(\\w+)\"/);\n if (getNameMatch) {\n const returnedName = getNameMatch[1];\n if (moduleNames.has(returnedName)) {\n moduleName = returnedName;\n }\n }\n }\n\n if (!moduleName) continue;\n\n // Collect method nodes\n const nodes = context.getNodesInFile(f);\n const methods = new Map<string, string>();\n for (const node of nodes) {\n if (node.kind === 'method' || node.kind === 'function') {\n methods.set(node.name, node.id);\n }\n }\n\n impls.push({ moduleName, methods, filePath: f });\n }\n\n return impls;\n}\n\n// \u2500\u2500 Bridge Implementation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport const turboModulesBridge: BridgeResolver = {\n name: 'turbomodules-bridge',\n\n detect(context: ResolutionContext): boolean {\n const files = context.getAllFiles();\n // Check for Native*.ts spec files\n for (const f of files) {\n const fileName = f.split('/').pop() ?? '';\n if (fileName.match(/^Native\\w+\\.(ts|tsx|js)$/)) {\n const content = context.readFile(f);\n if (content && content.includes('TurboModule')) {\n return true;\n }\n }\n }\n return false;\n },\n\n resolve(context: ResolutionContext): SynthesizedEdge[] {\n const edges: SynthesizedEdge[] = [];\n\n const specs = findTurboModuleSpecs(context);\n if (specs.length === 0) return edges;\n\n const moduleNames = new Set(specs.map(s => s.moduleName));\n const impls = findNativeImpls(context, moduleNames);\n\n // Match spec methods to native implementations\n for (const spec of specs) {\n const matchingImpls = impls.filter(i => i.moduleName === spec.moduleName);\n\n for (const impl of matchingImpls) {\n for (const method of spec.methods) {\n const nativeNodeId = impl.methods.get(method);\n if (!nativeNodeId) continue;\n\n // Find JS call sites that import and use this module\n const callSites = findCallSitesForModule(context, spec.moduleName, method);\n\n for (const callSiteId of callSites) {\n edges.push({\n source: callSiteId,\n target: nativeNodeId,\n kind: 'calls',\n confidence: 'inferred',\n confidenceScore: 0.9,\n metadata: {\n synthesizedBy: 'turbomodules-bridge',\n provenance: 'heuristic',\n moduleName: spec.moduleName,\n methodName: method,\n specFile: spec.specFilePath,\n },\n });\n }\n\n // Also link spec interface to native impl\n if (spec.specNodeId) {\n edges.push({\n source: spec.specNodeId,\n target: nativeNodeId,\n kind: 'references',\n confidence: 'inferred',\n confidenceScore: 0.9,\n metadata: {\n synthesizedBy: 'turbomodules-bridge',\n provenance: 'heuristic',\n moduleName: spec.moduleName,\n methodName: method,\n },\n });\n }\n }\n }\n }\n\n return edges;\n },\n};\n\n/**\n * Find JS/TS call sites that use a specific TurboModule method.\n */\nfunction findCallSitesForModule(\n context: ResolutionContext,\n moduleName: string,\n methodName: string\n): string[] {\n const callSiteIds: string[] = [];\n const files = context.getAllFiles();\n\n for (const f of files) {\n if (!f.endsWith('.ts') && !f.endsWith('.tsx') && !f.endsWith('.js') && !f.endsWith('.jsx')) {\n continue;\n }\n\n const content = context.readFile(f);\n if (!content) continue;\n\n // Check if file imports the Native module\n const importPattern = new RegExp(`import\\\\s+\\\\w+\\\\s+from\\\\s+['\"]\\\\.*/Native${moduleName}['\"]`);\n if (!importPattern.test(content)) continue;\n\n // Find calls to the method\n const callRegex = new RegExp(`\\\\w+\\\\.${methodName}\\\\s*\\\\(`, 'g');\n let match: RegExpExecArray | null;\n const nodes = context.getNodesInFile(f);\n\n while ((match = callRegex.exec(content)) !== null) {\n const lineNum = content.slice(0, match.index).split('\\n').length;\n const enclosing = nodes.find(\n n => (n.kind === 'function' || n.kind === 'method') &&\n n.startLine <= lineNum && n.endLine >= lineNum\n );\n if (enclosing && !callSiteIds.includes(enclosing.id)) {\n callSiteIds.push(enclosing.id);\n }\n }\n }\n\n return callSiteIds;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -23,8 +23,9 @@ __export(resolution_exports, {
23
23
  module.exports = __toCommonJS(resolution_exports);
24
24
  var import_name_matcher = require("./name-matcher");
25
25
  var import_errors = require("../errors");
26
+ var import_bridges = require("./bridges");
26
27
  class ReferenceResolver {
27
- constructor(db, config) {
28
+ constructor(db, config, projectRoot) {
28
29
  // Warm caches for O(1) lookup
29
30
  this.nameCache = /* @__PURE__ */ new Map();
30
31
  this.qualifiedNameCache = /* @__PURE__ */ new Map();
@@ -36,6 +37,7 @@ class ReferenceResolver {
36
37
  this.cacheWarmed = false;
37
38
  this.db = db;
38
39
  this.config = config;
40
+ this.projectRoot = projectRoot ?? "";
39
41
  }
40
42
  /**
41
43
  * Pre-load all nodes into Maps for O(1) lookup.
@@ -93,13 +95,18 @@ class ReferenceResolver {
93
95
  const rawDb = this.db.db;
94
96
  const remaining = rawDb.get("SELECT COUNT(*) as c FROM unresolved_refs")?.c ?? 0;
95
97
  const total = resolvedCount + remaining;
98
+ let bridgeResult;
99
+ if (this.projectRoot) {
100
+ bridgeResult = this._runBridgeResolvers();
101
+ }
96
102
  const durationMs = Date.now() - start;
97
103
  (0, import_errors.logDebug)(`ReferenceResolver: resolved ${resolvedCount}/${total} refs in ${durationMs}ms`);
98
104
  return {
99
105
  resolved: resolvedCount,
100
106
  unresolved: remaining,
101
107
  total,
102
- durationMs
108
+ durationMs,
109
+ bridgeResult
103
110
  };
104
111
  }
105
112
  /**
@@ -376,6 +383,58 @@ class ReferenceResolver {
376
383
  updatedAt: row.updated_at
377
384
  };
378
385
  }
386
+ // ── Bridge Resolution ──────────────────────────────────────────────────────
387
+ /**
388
+ * Run cross-language bridge resolvers to synthesize edges between
389
+ * symbols in different languages (Swift ↔ ObjC, JS ↔ Native, etc.).
390
+ */
391
+ _runBridgeResolvers() {
392
+ const context = this._buildBridgeContext();
393
+ return (0, import_bridges.runBridgeResolvers)(context, this.db);
394
+ }
395
+ /**
396
+ * Build a ResolutionContext for bridge resolvers using the warm caches.
397
+ */
398
+ _buildBridgeContext() {
399
+ const fs = require("fs");
400
+ const path = require("path");
401
+ const projectRoot = this.projectRoot;
402
+ const db = this.db;
403
+ const nameCache = this.nameCache;
404
+ const kindCache = this.kindCache;
405
+ const fileCache = /* @__PURE__ */ new Map();
406
+ return {
407
+ getNodesInFile(filePath) {
408
+ return db.getNodesByFile(filePath);
409
+ },
410
+ getNodesByName(name) {
411
+ return nameCache.get(name) ?? [];
412
+ },
413
+ getNodesByKind(kind) {
414
+ return kindCache.get(kind) ?? [];
415
+ },
416
+ fileExists(filePath) {
417
+ return fs.existsSync(path.join(projectRoot, filePath));
418
+ },
419
+ readFile(filePath) {
420
+ if (fileCache.has(filePath)) return fileCache.get(filePath);
421
+ try {
422
+ const content = fs.readFileSync(path.join(projectRoot, filePath), "utf8");
423
+ fileCache.set(filePath, content);
424
+ return content;
425
+ } catch {
426
+ fileCache.set(filePath, null);
427
+ return null;
428
+ }
429
+ },
430
+ getProjectRoot() {
431
+ return projectRoot;
432
+ },
433
+ getAllFiles() {
434
+ return db.getAllFiles().map((f) => f.path);
435
+ }
436
+ };
437
+ }
379
438
  }
380
439
  // Annotate the CommonJS export names for ESM import in node:
381
440
  0 && (module.exports = {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/resolution/index.ts"],
4
- "sourcesContent": ["/**\n * KiroGraph Reference Resolver\n *\n * Implements the warm-cache resolution engine with multiple strategies.\n * Mirrors CodeGraph src/resolution/index.ts\n */\n\nimport type { Node, NodeKind, Edge } from '../types';\nimport type { GraphDatabase } from '../db/database';\nimport type { KiroGraphConfig } from '../config';\nimport { matchReference } from './name-matcher';\nimport { logDebug, logWarn } from '../errors';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ResolutionResult {\n resolved: number;\n unresolved: number;\n total: number;\n durationMs: number;\n}\n\n// \u2500\u2500 ReferenceResolver \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ReferenceResolver {\n private db: GraphDatabase;\n private config: KiroGraphConfig;\n\n // Warm caches for O(1) lookup\n private nameCache: Map<string, Node[]> = new Map();\n private qualifiedNameCache: Map<string, Node> = new Map();\n private kindCache: Map<NodeKind, Node[]> = new Map();\n private lowerNameCache: Map<string, Node[]> = new Map();\n private nodeByIdCache: Map<string, Node> = new Map();\n // namespace prefix \u2192 first non-import node ID (for C#/Java namespace-level imports)\n private namespacePrefixCache: Map<string, string> = new Map();\n\n private cacheWarmed = false;\n\n constructor(db: GraphDatabase, config: KiroGraphConfig) {\n this.db = db;\n this.config = config;\n }\n\n /**\n * Pre-load all nodes into Maps for O(1) lookup.\n * Must be called before resolveUnresolvedRefs() for best performance.\n */\n warmCaches(): void {\n this.nameCache.clear();\n this.qualifiedNameCache.clear();\n this.kindCache.clear();\n this.lowerNameCache.clear();\n this.nodeByIdCache.clear();\n this.namespacePrefixCache.clear();\n\n // Access the underlying db instance to query all nodes\n const rawDb = (this.db as any).db;\n const rows: any[] = rawDb.all('SELECT * FROM nodes');\n\n for (const row of rows) {\n const node: Node = this._rowToNode(row);\n\n // nameCache\n const nameList = this.nameCache.get(node.name) ?? [];\n nameList.push(node);\n this.nameCache.set(node.name, nameList);\n\n // qualifiedNameCache\n if (node.qualifiedName) {\n this.qualifiedNameCache.set(node.qualifiedName, node);\n }\n\n // kindCache\n const kindList = this.kindCache.get(node.kind) ?? [];\n kindList.push(node);\n this.kindCache.set(node.kind, kindList);\n\n // lowerNameCache\n const lower = node.name.toLowerCase();\n const lowerList = this.lowerNameCache.get(lower) ?? [];\n lowerList.push(node);\n this.lowerNameCache.set(lower, lowerList);\n\n // nodeByIdCache\n this.nodeByIdCache.set(node.id, node);\n }\n\n // Build namespace prefix cache for C#/Java namespace-level import resolution.\n // For each class/interface with a dotted qualifiedName, record every ancestor\n // namespace prefix \u2192 the node ID, so \"using MyApp.Services\" resolves O(1).\n for (const [qualName, node] of this.qualifiedNameCache) {\n if (node.kind === 'class' || node.kind === 'interface' || node.kind === 'namespace' || node.kind === 'module') {\n const parts = qualName.split('.');\n for (let k = 1; k < parts.length; k++) {\n const prefix = parts.slice(0, k).join('.');\n if (!this.namespacePrefixCache.has(prefix)) {\n this.namespacePrefixCache.set(prefix, node.id);\n }\n }\n }\n }\n\n this.cacheWarmed = true;\n logDebug(`ReferenceResolver: warmed caches with ${rows.length} nodes`);\n }\n\n /**\n * Resolve all pending unresolved references.\n * Warms caches first, then processes all pending refs.\n * Returns a ResolutionResult with counts and duration.\n */\n async resolveAll(onProgress?: (current: number, total: number) => void): Promise<ResolutionResult> {\n const start = Date.now();\n\n this.warmCaches();\n const resolvedCount = await this.resolveUnresolvedRefs(onProgress);\n\n // Count remaining unresolved\n const rawDb = (this.db as any).db;\n const remaining = rawDb.get('SELECT COUNT(*) as c FROM unresolved_refs')?.c ?? 0;\n const total = resolvedCount + remaining;\n\n const durationMs = Date.now() - start;\n logDebug(`ReferenceResolver: resolved ${resolvedCount}/${total} refs in ${durationMs}ms`);\n\n return {\n resolved: resolvedCount,\n unresolved: remaining,\n total,\n durationMs,\n };\n }\n\n /**\n * Process all pending unresolved references using warm caches.\n * Returns the count of newly resolved edges.\n */\n async resolveUnresolvedRefs(onProgress?: (current: number, total: number) => void): Promise<number> {\n if (!this.cacheWarmed) {\n this.warmCaches();\n }\n\n const rawDb = (this.db as any).db;\n const refs: any[] = rawDb.all('SELECT * FROM unresolved_refs');\n let resolved = 0;\n const total = refs.length;\n\n // Process in batched transactions to avoid WASM heap exhaustion.\n // Without batching, each individual write allocates journal pages in the\n // WASM linear memory, which can exceed the 2GB limit on large codebases.\n const BATCH_SIZE = 1000;\n\n // Skip the expensive \"scan all nodes\" fuzzy fallback for very large graphs.\n // The O(N*M) cost is prohibitive and the WASM heap cannot sustain it.\n const FUZZY_ALL_NODES_LIMIT = 200_000;\n const skipFullFuzzy = this.nodeByIdCache.size > FUZZY_ALL_NODES_LIMIT;\n if (skipFullFuzzy) {\n logDebug(`ReferenceResolver: skipping full-scan fuzzy (${this.nodeByIdCache.size} nodes exceeds ${FUZZY_ALL_NODES_LIMIT} limit)`);\n }\n\n for (let batchStart = 0; batchStart < refs.length; batchStart += BATCH_SIZE) {\n const batchEnd = Math.min(batchStart + BATCH_SIZE, refs.length);\n\n // Wrap each batch in a transaction \u2014 dramatically reduces write amplification\n rawDb.run('BEGIN');\n try {\n for (let i = batchStart; i < batchEnd; i++) {\n const ref = refs[i];\n onProgress?.(i + 1, total);\n const {\n id: refId,\n source_id: sourceId,\n ref_name: refName,\n ref_kind: refKind,\n file_path: filePath,\n line,\n column,\n } = ref;\n\n const attemptedStrategies: string[] = [];\n let targetId: string | null = null;\n\n if (refKind === 'import') {\n attemptedStrategies.push('import-path');\n targetId = this._resolveImportPath(refName, filePath);\n } else if (refKind === 'extends' || refKind === 'implements') {\n attemptedStrategies.push('type-name');\n targetId = this._resolveTypeName(refName);\n } else {\n attemptedStrategies.push('framework');\n\n // Strategy 2: Qualified name match (confidence 0.95)\n attemptedStrategies.push('qualified');\n const qualifiedNode = this.qualifiedNameCache.get(refName);\n if (qualifiedNode) {\n targetId = qualifiedNode.id;\n }\n\n // Strategy 3: Method call pattern (confidence 0.85)\n if (!targetId && refName.includes('.')) {\n attemptedStrategies.push('method');\n const methodPart = refName.slice(refName.lastIndexOf('.') + 1);\n const methodCandidates = this.nameCache.get(methodPart) ?? [];\n if (methodCandidates.length > 0) {\n targetId = methodCandidates[0].id;\n }\n }\n\n // Strategy 4: Exact name match (confidence 0.9)\n if (!targetId) {\n attemptedStrategies.push('exact');\n const exactCandidates = this.nameCache.get(refName) ?? [];\n if (exactCandidates.length > 0) {\n targetId = exactCandidates[0].id;\n }\n }\n\n // Strategy 5: Fuzzy / lowercase match (confidence 0.5)\n if (!targetId) {\n attemptedStrategies.push('fuzzy');\n const threshold = this.config.fuzzyResolutionThreshold ?? 0.5;\n const lowerRef = refName.toLowerCase();\n const fuzzyCandidates = this.lowerNameCache.get(lowerRef) ?? [];\n\n if (fuzzyCandidates.length > 0) {\n const match = matchReference(refName, fuzzyCandidates, threshold);\n if (match) {\n targetId = match.nodeId;\n }\n }\n\n // Full-scan fuzzy: only for smaller graphs (O(N*M) is too expensive otherwise)\n if (!targetId && !skipFullFuzzy) {\n const allCandidates = [...this.nodeByIdCache.values()];\n const match = matchReference(refName, allCandidates, threshold);\n if (match) {\n targetId = match.nodeId;\n }\n }\n }\n }\n\n if (targetId) {\n const edgeKind = refKind === 'import' ? 'imports'\n : refKind === 'extends' ? 'extends'\n : refKind === 'implements' ? 'implements'\n : 'calls';\n const edge: Edge = {\n source: sourceId,\n target: targetId,\n kind: edgeKind,\n line: line ?? undefined,\n column: column ?? undefined,\n };\n this.db.insertEdge(edge);\n rawDb.run('DELETE FROM unresolved_refs WHERE id = ?', [refId]);\n resolved++;\n } else {\n const strategiesJson = JSON.stringify(attemptedStrategies);\n try {\n rawDb.run(\n 'UPDATE unresolved_refs SET attempted_strategies = ? WHERE id = ?',\n [strategiesJson, refId]\n );\n } catch {\n logWarn(`ReferenceResolver: failed to record attempted strategies for ref ${refId}`);\n }\n }\n }\n rawDb.run('COMMIT');\n } catch (err) {\n // Roll back the failed batch but continue with remaining batches\n try { rawDb.run('ROLLBACK'); } catch { /* already rolled back */ }\n logWarn(`ReferenceResolver: batch ${batchStart}-${batchEnd} failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return resolved;\n }\n\n /**\n * Invalidate cache entries for all nodes belonging to the given file.\n * Call this when a file is re-indexed to prevent stale cache hits.\n */\n invalidateFile(filePath: string): void {\n const nodesToRemove: Node[] = [];\n\n for (const node of this.nodeByIdCache.values()) {\n if (node.filePath === filePath) {\n nodesToRemove.push(node);\n }\n }\n\n for (const node of nodesToRemove) {\n // Remove from nodeByIdCache\n this.nodeByIdCache.delete(node.id);\n\n // Remove from nameCache\n const nameList = this.nameCache.get(node.name);\n if (nameList) {\n const filtered = nameList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.nameCache.delete(node.name);\n } else {\n this.nameCache.set(node.name, filtered);\n }\n }\n\n // Remove from qualifiedNameCache\n if (node.qualifiedName) {\n const cached = this.qualifiedNameCache.get(node.qualifiedName);\n if (cached?.id === node.id) {\n this.qualifiedNameCache.delete(node.qualifiedName);\n }\n }\n\n // Remove from kindCache\n const kindList = this.kindCache.get(node.kind);\n if (kindList) {\n const filtered = kindList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.kindCache.delete(node.kind);\n } else {\n this.kindCache.set(node.kind, filtered);\n }\n }\n\n // Remove from lowerNameCache\n const lower = node.name.toLowerCase();\n const lowerList = this.lowerNameCache.get(lower);\n if (lowerList) {\n const filtered = lowerList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.lowerNameCache.delete(lower);\n } else {\n this.lowerNameCache.set(lower, filtered);\n }\n }\n }\n\n logDebug(`ReferenceResolver: invalidated ${nodesToRemove.length} cache entries for ${filePath}`);\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve an import path to a node ID.\n *\n * Handles three cases:\n * 1. Relative paths (JS/TS/Go/\u2026) \u2014 resolved via the file tree.\n * 2. Fully-qualified type imports (Java `import com.example.Foo`) \u2014 exact qualifiedName lookup,\n * then name+namespace-prefix match.\n * 3. Namespace-level imports (C# `using MyApp.Services`) \u2014 namespace node lookup, then\n * namespace prefix cache (O(1)) to find any class in that namespace.\n */\n private _resolveImportPath(importPath: string, sourceFilePath: string): string | null {\n // \u2500\u2500 1. Relative path (JS/TS etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (importPath.startsWith('.')) {\n const sourceDir = sourceFilePath.replace(/[^/]+$/, '');\n const segments = (sourceDir + importPath).split('/');\n const normalized: string[] = [];\n for (const seg of segments) {\n if (seg === '..') normalized.pop();\n else if (seg !== '.') normalized.push(seg);\n }\n const basePath = normalized.join('/');\n const candidates = [\n basePath,\n basePath + '.ts', basePath + '.tsx',\n basePath + '.js', basePath + '.jsx',\n basePath + '/index.ts', basePath + '/index.tsx', basePath + '/index.js',\n ];\n const rawDb = (this.db as any).db;\n for (const candidate of candidates) {\n const row = rawDb.get('SELECT id FROM nodes WHERE file_path = ? LIMIT 1', [candidate]);\n if (row) return row.id;\n }\n return null;\n }\n\n // \u2500\u2500 2. Wildcard namespace import (`import com.example.*`, `using static \u2026`) \u2500\n if (importPath.endsWith('.*') || importPath.endsWith('*')) {\n const ns = importPath.replace(/\\.\\*$/, '').replace(/\\*$/, '');\n return this.namespacePrefixCache.get(ns) ?? null;\n }\n\n // \u2500\u2500 3. Exact qualifiedName match (Java `import com.example.Foo`) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const exact = this.qualifiedNameCache.get(importPath);\n if (exact) return exact.id;\n\n // \u2500\u2500 4. Name + namespace prefix (Java: last segment is the type name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const lastDot = importPath.lastIndexOf('.');\n if (lastDot > 0) {\n const typeName = importPath.slice(lastDot + 1);\n const namespace = importPath.slice(0, lastDot);\n const candidates = this.nameCache.get(typeName) ?? [];\n for (const candidate of candidates) {\n if (candidate.qualifiedName && candidate.qualifiedName.startsWith(namespace)) {\n return candidate.id;\n }\n }\n }\n\n // \u2500\u2500 5. Namespace-level import (C# `using MyApp.Services`) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // First check for an explicit namespace node with this name\n const nsCandidates = this.nameCache.get(importPath.split('.').pop() ?? '') ?? [];\n for (const candidate of nsCandidates) {\n if (candidate.kind === 'namespace' && candidate.name === importPath) return candidate.id;\n }\n // Then fall back to the prefix cache: return any class/interface in this namespace\n return this.namespacePrefixCache.get(importPath) ?? null;\n }\n\n /**\n * Resolve a bare type name to a node ID.\n * Used for extends/implements refs where we have only the unqualified type name.\n * Prefers class/interface/trait/protocol nodes over other kinds.\n */\n private _resolveTypeName(name: string): string | null {\n const candidates = this.nameCache.get(name) ?? [];\n if (candidates.length > 0) {\n const preferred = candidates.find(n =>\n n.kind === 'class' || n.kind === 'interface' || n.kind === 'trait' || n.kind === 'protocol'\n );\n return (preferred ?? candidates[0]).id;\n }\n // Try as a fully-qualified name\n const qualified = this.qualifiedNameCache.get(name);\n if (qualified) return qualified.id;\n return null;\n }\n\n /**\n * Convert a raw DB row to a Node object.\n */\n private _rowToNode(row: any): Node {\n return {\n id: row.id,\n kind: row.kind,\n name: row.name,\n qualifiedName: row.qualified_name,\n filePath: row.file_path,\n language: row.language,\n startLine: row.start_line,\n endLine: row.end_line,\n startColumn: row.start_column,\n endColumn: row.end_column,\n docstring: row.docstring ?? undefined,\n signature: row.signature ?? undefined,\n visibility: row.visibility ?? undefined,\n isExported: row.is_exported === 1,\n isAsync: row.is_async === 1,\n isStatic: row.is_static === 1,\n isAbstract: row.is_abstract === 1,\n decorators: row.decorators ? JSON.parse(row.decorators) : undefined,\n typeParameters: row.type_parameters ? JSON.parse(row.type_parameters) : undefined,\n updatedAt: row.updated_at,\n };\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * KiroGraph Reference Resolver\n *\n * Implements the warm-cache resolution engine with multiple strategies.\n * Mirrors CodeGraph src/resolution/index.ts\n */\n\nimport type { Node, NodeKind, Edge } from '../types';\nimport type { GraphDatabase } from '../db/database';\nimport type { KiroGraphConfig } from '../config';\nimport { matchReference } from './name-matcher';\nimport { logDebug, logWarn } from '../errors';\nimport { runBridgeResolvers, type BridgeResolutionResult } from './bridges';\n\n// \u2500\u2500 Types \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ResolutionResult {\n resolved: number;\n unresolved: number;\n total: number;\n durationMs: number;\n bridgeResult?: BridgeResolutionResult;\n}\n\n// \u2500\u2500 ReferenceResolver \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport class ReferenceResolver {\n private db: GraphDatabase;\n private config: KiroGraphConfig;\n private projectRoot: string;\n\n // Warm caches for O(1) lookup\n private nameCache: Map<string, Node[]> = new Map();\n private qualifiedNameCache: Map<string, Node> = new Map();\n private kindCache: Map<NodeKind, Node[]> = new Map();\n private lowerNameCache: Map<string, Node[]> = new Map();\n private nodeByIdCache: Map<string, Node> = new Map();\n // namespace prefix \u2192 first non-import node ID (for C#/Java namespace-level imports)\n private namespacePrefixCache: Map<string, string> = new Map();\n\n private cacheWarmed = false;\n\n constructor(db: GraphDatabase, config: KiroGraphConfig, projectRoot?: string) {\n this.db = db;\n this.config = config;\n this.projectRoot = projectRoot ?? '';\n }\n\n /**\n * Pre-load all nodes into Maps for O(1) lookup.\n * Must be called before resolveUnresolvedRefs() for best performance.\n */\n warmCaches(): void {\n this.nameCache.clear();\n this.qualifiedNameCache.clear();\n this.kindCache.clear();\n this.lowerNameCache.clear();\n this.nodeByIdCache.clear();\n this.namespacePrefixCache.clear();\n\n // Access the underlying db instance to query all nodes\n const rawDb = (this.db as any).db;\n const rows: any[] = rawDb.all('SELECT * FROM nodes');\n\n for (const row of rows) {\n const node: Node = this._rowToNode(row);\n\n // nameCache\n const nameList = this.nameCache.get(node.name) ?? [];\n nameList.push(node);\n this.nameCache.set(node.name, nameList);\n\n // qualifiedNameCache\n if (node.qualifiedName) {\n this.qualifiedNameCache.set(node.qualifiedName, node);\n }\n\n // kindCache\n const kindList = this.kindCache.get(node.kind) ?? [];\n kindList.push(node);\n this.kindCache.set(node.kind, kindList);\n\n // lowerNameCache\n const lower = node.name.toLowerCase();\n const lowerList = this.lowerNameCache.get(lower) ?? [];\n lowerList.push(node);\n this.lowerNameCache.set(lower, lowerList);\n\n // nodeByIdCache\n this.nodeByIdCache.set(node.id, node);\n }\n\n // Build namespace prefix cache for C#/Java namespace-level import resolution.\n // For each class/interface with a dotted qualifiedName, record every ancestor\n // namespace prefix \u2192 the node ID, so \"using MyApp.Services\" resolves O(1).\n for (const [qualName, node] of this.qualifiedNameCache) {\n if (node.kind === 'class' || node.kind === 'interface' || node.kind === 'namespace' || node.kind === 'module') {\n const parts = qualName.split('.');\n for (let k = 1; k < parts.length; k++) {\n const prefix = parts.slice(0, k).join('.');\n if (!this.namespacePrefixCache.has(prefix)) {\n this.namespacePrefixCache.set(prefix, node.id);\n }\n }\n }\n }\n\n this.cacheWarmed = true;\n logDebug(`ReferenceResolver: warmed caches with ${rows.length} nodes`);\n }\n\n /**\n * Resolve all pending unresolved references.\n * Warms caches first, then processes all pending refs.\n * Returns a ResolutionResult with counts and duration.\n */\n async resolveAll(onProgress?: (current: number, total: number) => void): Promise<ResolutionResult> {\n const start = Date.now();\n\n this.warmCaches();\n const resolvedCount = await this.resolveUnresolvedRefs(onProgress);\n\n // Count remaining unresolved\n const rawDb = (this.db as any).db;\n const remaining = rawDb.get('SELECT COUNT(*) as c FROM unresolved_refs')?.c ?? 0;\n const total = resolvedCount + remaining;\n\n // Run cross-language bridge resolvers after standard resolution\n let bridgeResult: BridgeResolutionResult | undefined;\n if (this.projectRoot) {\n bridgeResult = this._runBridgeResolvers();\n }\n\n const durationMs = Date.now() - start;\n logDebug(`ReferenceResolver: resolved ${resolvedCount}/${total} refs in ${durationMs}ms`);\n\n return {\n resolved: resolvedCount,\n unresolved: remaining,\n total,\n durationMs,\n bridgeResult,\n };\n }\n\n /**\n * Process all pending unresolved references using warm caches.\n * Returns the count of newly resolved edges.\n */\n async resolveUnresolvedRefs(onProgress?: (current: number, total: number) => void): Promise<number> {\n if (!this.cacheWarmed) {\n this.warmCaches();\n }\n\n const rawDb = (this.db as any).db;\n const refs: any[] = rawDb.all('SELECT * FROM unresolved_refs');\n let resolved = 0;\n const total = refs.length;\n\n // Process in batched transactions to avoid WASM heap exhaustion.\n // Without batching, each individual write allocates journal pages in the\n // WASM linear memory, which can exceed the 2GB limit on large codebases.\n const BATCH_SIZE = 1000;\n\n // Skip the expensive \"scan all nodes\" fuzzy fallback for very large graphs.\n // The O(N*M) cost is prohibitive and the WASM heap cannot sustain it.\n const FUZZY_ALL_NODES_LIMIT = 200_000;\n const skipFullFuzzy = this.nodeByIdCache.size > FUZZY_ALL_NODES_LIMIT;\n if (skipFullFuzzy) {\n logDebug(`ReferenceResolver: skipping full-scan fuzzy (${this.nodeByIdCache.size} nodes exceeds ${FUZZY_ALL_NODES_LIMIT} limit)`);\n }\n\n for (let batchStart = 0; batchStart < refs.length; batchStart += BATCH_SIZE) {\n const batchEnd = Math.min(batchStart + BATCH_SIZE, refs.length);\n\n // Wrap each batch in a transaction \u2014 dramatically reduces write amplification\n rawDb.run('BEGIN');\n try {\n for (let i = batchStart; i < batchEnd; i++) {\n const ref = refs[i];\n onProgress?.(i + 1, total);\n const {\n id: refId,\n source_id: sourceId,\n ref_name: refName,\n ref_kind: refKind,\n file_path: filePath,\n line,\n column,\n } = ref;\n\n const attemptedStrategies: string[] = [];\n let targetId: string | null = null;\n\n if (refKind === 'import') {\n attemptedStrategies.push('import-path');\n targetId = this._resolveImportPath(refName, filePath);\n } else if (refKind === 'extends' || refKind === 'implements') {\n attemptedStrategies.push('type-name');\n targetId = this._resolveTypeName(refName);\n } else {\n attemptedStrategies.push('framework');\n\n // Strategy 2: Qualified name match (confidence 0.95)\n attemptedStrategies.push('qualified');\n const qualifiedNode = this.qualifiedNameCache.get(refName);\n if (qualifiedNode) {\n targetId = qualifiedNode.id;\n }\n\n // Strategy 3: Method call pattern (confidence 0.85)\n if (!targetId && refName.includes('.')) {\n attemptedStrategies.push('method');\n const methodPart = refName.slice(refName.lastIndexOf('.') + 1);\n const methodCandidates = this.nameCache.get(methodPart) ?? [];\n if (methodCandidates.length > 0) {\n targetId = methodCandidates[0].id;\n }\n }\n\n // Strategy 4: Exact name match (confidence 0.9)\n if (!targetId) {\n attemptedStrategies.push('exact');\n const exactCandidates = this.nameCache.get(refName) ?? [];\n if (exactCandidates.length > 0) {\n targetId = exactCandidates[0].id;\n }\n }\n\n // Strategy 5: Fuzzy / lowercase match (confidence 0.5)\n if (!targetId) {\n attemptedStrategies.push('fuzzy');\n const threshold = this.config.fuzzyResolutionThreshold ?? 0.5;\n const lowerRef = refName.toLowerCase();\n const fuzzyCandidates = this.lowerNameCache.get(lowerRef) ?? [];\n\n if (fuzzyCandidates.length > 0) {\n const match = matchReference(refName, fuzzyCandidates, threshold);\n if (match) {\n targetId = match.nodeId;\n }\n }\n\n // Full-scan fuzzy: only for smaller graphs (O(N*M) is too expensive otherwise)\n if (!targetId && !skipFullFuzzy) {\n const allCandidates = [...this.nodeByIdCache.values()];\n const match = matchReference(refName, allCandidates, threshold);\n if (match) {\n targetId = match.nodeId;\n }\n }\n }\n }\n\n if (targetId) {\n const edgeKind = refKind === 'import' ? 'imports'\n : refKind === 'extends' ? 'extends'\n : refKind === 'implements' ? 'implements'\n : 'calls';\n const edge: Edge = {\n source: sourceId,\n target: targetId,\n kind: edgeKind,\n line: line ?? undefined,\n column: column ?? undefined,\n };\n this.db.insertEdge(edge);\n rawDb.run('DELETE FROM unresolved_refs WHERE id = ?', [refId]);\n resolved++;\n } else {\n const strategiesJson = JSON.stringify(attemptedStrategies);\n try {\n rawDb.run(\n 'UPDATE unresolved_refs SET attempted_strategies = ? WHERE id = ?',\n [strategiesJson, refId]\n );\n } catch {\n logWarn(`ReferenceResolver: failed to record attempted strategies for ref ${refId}`);\n }\n }\n }\n rawDb.run('COMMIT');\n } catch (err) {\n // Roll back the failed batch but continue with remaining batches\n try { rawDb.run('ROLLBACK'); } catch { /* already rolled back */ }\n logWarn(`ReferenceResolver: batch ${batchStart}-${batchEnd} failed: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n return resolved;\n }\n\n /**\n * Invalidate cache entries for all nodes belonging to the given file.\n * Call this when a file is re-indexed to prevent stale cache hits.\n */\n invalidateFile(filePath: string): void {\n const nodesToRemove: Node[] = [];\n\n for (const node of this.nodeByIdCache.values()) {\n if (node.filePath === filePath) {\n nodesToRemove.push(node);\n }\n }\n\n for (const node of nodesToRemove) {\n // Remove from nodeByIdCache\n this.nodeByIdCache.delete(node.id);\n\n // Remove from nameCache\n const nameList = this.nameCache.get(node.name);\n if (nameList) {\n const filtered = nameList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.nameCache.delete(node.name);\n } else {\n this.nameCache.set(node.name, filtered);\n }\n }\n\n // Remove from qualifiedNameCache\n if (node.qualifiedName) {\n const cached = this.qualifiedNameCache.get(node.qualifiedName);\n if (cached?.id === node.id) {\n this.qualifiedNameCache.delete(node.qualifiedName);\n }\n }\n\n // Remove from kindCache\n const kindList = this.kindCache.get(node.kind);\n if (kindList) {\n const filtered = kindList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.kindCache.delete(node.kind);\n } else {\n this.kindCache.set(node.kind, filtered);\n }\n }\n\n // Remove from lowerNameCache\n const lower = node.name.toLowerCase();\n const lowerList = this.lowerNameCache.get(lower);\n if (lowerList) {\n const filtered = lowerList.filter(n => n.id !== node.id);\n if (filtered.length === 0) {\n this.lowerNameCache.delete(lower);\n } else {\n this.lowerNameCache.set(lower, filtered);\n }\n }\n }\n\n logDebug(`ReferenceResolver: invalidated ${nodesToRemove.length} cache entries for ${filePath}`);\n }\n\n // \u2500\u2500 Private helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Resolve an import path to a node ID.\n *\n * Handles three cases:\n * 1. Relative paths (JS/TS/Go/\u2026) \u2014 resolved via the file tree.\n * 2. Fully-qualified type imports (Java `import com.example.Foo`) \u2014 exact qualifiedName lookup,\n * then name+namespace-prefix match.\n * 3. Namespace-level imports (C# `using MyApp.Services`) \u2014 namespace node lookup, then\n * namespace prefix cache (O(1)) to find any class in that namespace.\n */\n private _resolveImportPath(importPath: string, sourceFilePath: string): string | null {\n // \u2500\u2500 1. Relative path (JS/TS etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (importPath.startsWith('.')) {\n const sourceDir = sourceFilePath.replace(/[^/]+$/, '');\n const segments = (sourceDir + importPath).split('/');\n const normalized: string[] = [];\n for (const seg of segments) {\n if (seg === '..') normalized.pop();\n else if (seg !== '.') normalized.push(seg);\n }\n const basePath = normalized.join('/');\n const candidates = [\n basePath,\n basePath + '.ts', basePath + '.tsx',\n basePath + '.js', basePath + '.jsx',\n basePath + '/index.ts', basePath + '/index.tsx', basePath + '/index.js',\n ];\n const rawDb = (this.db as any).db;\n for (const candidate of candidates) {\n const row = rawDb.get('SELECT id FROM nodes WHERE file_path = ? LIMIT 1', [candidate]);\n if (row) return row.id;\n }\n return null;\n }\n\n // \u2500\u2500 2. Wildcard namespace import (`import com.example.*`, `using static \u2026`) \u2500\n if (importPath.endsWith('.*') || importPath.endsWith('*')) {\n const ns = importPath.replace(/\\.\\*$/, '').replace(/\\*$/, '');\n return this.namespacePrefixCache.get(ns) ?? null;\n }\n\n // \u2500\u2500 3. Exact qualifiedName match (Java `import com.example.Foo`) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const exact = this.qualifiedNameCache.get(importPath);\n if (exact) return exact.id;\n\n // \u2500\u2500 4. Name + namespace prefix (Java: last segment is the type name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const lastDot = importPath.lastIndexOf('.');\n if (lastDot > 0) {\n const typeName = importPath.slice(lastDot + 1);\n const namespace = importPath.slice(0, lastDot);\n const candidates = this.nameCache.get(typeName) ?? [];\n for (const candidate of candidates) {\n if (candidate.qualifiedName && candidate.qualifiedName.startsWith(namespace)) {\n return candidate.id;\n }\n }\n }\n\n // \u2500\u2500 5. Namespace-level import (C# `using MyApp.Services`) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // First check for an explicit namespace node with this name\n const nsCandidates = this.nameCache.get(importPath.split('.').pop() ?? '') ?? [];\n for (const candidate of nsCandidates) {\n if (candidate.kind === 'namespace' && candidate.name === importPath) return candidate.id;\n }\n // Then fall back to the prefix cache: return any class/interface in this namespace\n return this.namespacePrefixCache.get(importPath) ?? null;\n }\n\n /**\n * Resolve a bare type name to a node ID.\n * Used for extends/implements refs where we have only the unqualified type name.\n * Prefers class/interface/trait/protocol nodes over other kinds.\n */\n private _resolveTypeName(name: string): string | null {\n const candidates = this.nameCache.get(name) ?? [];\n if (candidates.length > 0) {\n const preferred = candidates.find(n =>\n n.kind === 'class' || n.kind === 'interface' || n.kind === 'trait' || n.kind === 'protocol'\n );\n return (preferred ?? candidates[0]).id;\n }\n // Try as a fully-qualified name\n const qualified = this.qualifiedNameCache.get(name);\n if (qualified) return qualified.id;\n return null;\n }\n\n /**\n * Convert a raw DB row to a Node object.\n */\n private _rowToNode(row: any): Node {\n return {\n id: row.id,\n kind: row.kind,\n name: row.name,\n qualifiedName: row.qualified_name,\n filePath: row.file_path,\n language: row.language,\n startLine: row.start_line,\n endLine: row.end_line,\n startColumn: row.start_column,\n endColumn: row.end_column,\n docstring: row.docstring ?? undefined,\n signature: row.signature ?? undefined,\n visibility: row.visibility ?? undefined,\n isExported: row.is_exported === 1,\n isAsync: row.is_async === 1,\n isStatic: row.is_static === 1,\n isAbstract: row.is_abstract === 1,\n decorators: row.decorators ? JSON.parse(row.decorators) : undefined,\n typeParameters: row.type_parameters ? JSON.parse(row.type_parameters) : undefined,\n updatedAt: row.updated_at,\n };\n }\n\n // \u2500\u2500 Bridge Resolution \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Run cross-language bridge resolvers to synthesize edges between\n * symbols in different languages (Swift \u2194 ObjC, JS \u2194 Native, etc.).\n */\n private _runBridgeResolvers(): BridgeResolutionResult {\n const context = this._buildBridgeContext();\n return runBridgeResolvers(context, this.db);\n }\n\n /**\n * Build a ResolutionContext for bridge resolvers using the warm caches.\n */\n private _buildBridgeContext(): import('../frameworks/types').ResolutionContext {\n const fs = require('fs') as typeof import('fs');\n const path = require('path') as typeof import('path');\n const projectRoot = this.projectRoot;\n const db = this.db;\n const nameCache = this.nameCache;\n const kindCache = this.kindCache;\n const fileCache = new Map<string, string | null>();\n\n return {\n getNodesInFile(filePath: string): Node[] {\n return db.getNodesByFile(filePath);\n },\n getNodesByName(name: string): Node[] {\n return nameCache.get(name) ?? [];\n },\n getNodesByKind(kind: Node['kind']): Node[] {\n return kindCache.get(kind) ?? [];\n },\n fileExists(filePath: string): boolean {\n return fs.existsSync(path.join(projectRoot, filePath));\n },\n readFile(filePath: string): string | null {\n if (fileCache.has(filePath)) return fileCache.get(filePath)!;\n try {\n const content = fs.readFileSync(path.join(projectRoot, filePath), 'utf8');\n fileCache.set(filePath, content);\n return content;\n } catch {\n fileCache.set(filePath, null);\n return null;\n }\n },\n getProjectRoot(): string {\n return projectRoot;\n },\n getAllFiles(): string[] {\n return db.getAllFiles().map((f: any) => f.path);\n },\n };\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,164 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var attack_surface_exports = {};
20
+ __export(attack_surface_exports, {
21
+ AttackSurfaceAnalyzer: () => AttackSurfaceAnalyzer
22
+ });
23
+ module.exports = __toCommonJS(attack_surface_exports);
24
+ const AUTH_PATTERNS = [
25
+ "auth",
26
+ "authenticate",
27
+ "middleware",
28
+ "guard",
29
+ "protect",
30
+ "requirelogin",
31
+ "isloggedin",
32
+ "verifytoken",
33
+ "checkauth",
34
+ "ensureauth"
35
+ ];
36
+ const PUBLIC_ROUTE_PATTERNS = ["/api/", "/v1/", "/v2/", "/v3/", "/graphql", "/rest/"];
37
+ const INTERNAL_ROUTE_PATTERNS = ["/internal/", "/admin/"];
38
+ class AttackSurfaceAnalyzer {
39
+ constructor(db) {
40
+ this.db = db;
41
+ }
42
+ async analyze() {
43
+ const rawDb = this.db.getRawDb();
44
+ const routeRows = rawDb.all(
45
+ `SELECT id, name, file_path FROM nodes WHERE kind = 'route'`
46
+ );
47
+ if (routeRows.length === 0) {
48
+ return {
49
+ totalRoutes: 0,
50
+ publicRoutes: 0,
51
+ authenticatedRoutes: 0,
52
+ routesWithVulns: 0,
53
+ criticalPaths: [],
54
+ allRoutes: []
55
+ };
56
+ }
57
+ const entries = [];
58
+ for (const route of routeRows) {
59
+ const reachableDeps = rawDb.all(
60
+ `WITH RECURSIVE reachable(node_id, depth) AS (
61
+ SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')
62
+ UNION
63
+ SELECT e.target, r.depth + 1
64
+ FROM edges e
65
+ JOIN reachable r ON e.source = r.node_id
66
+ WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')
67
+ )
68
+ SELECT d.node_id, d.package_name, MIN(r.depth) as hop_count
69
+ FROM reachable r
70
+ JOIN sec_dependencies d ON d.node_id = r.node_id
71
+ GROUP BY d.node_id, d.package_name`,
72
+ [route.id]
73
+ );
74
+ const vulnerableDeps = [];
75
+ for (const dep of reachableDeps) {
76
+ const vulnRows = rawDb.all(
77
+ `SELECT v.cve_id, d.package_name, v.severity_score, v.epss_score, v.risk_score, r.verdict
78
+ FROM sec_vulnerabilities v
79
+ JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'
80
+ JOIN sec_dependencies d ON d.node_id = e.source
81
+ LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id
82
+ WHERE d.node_id = ?
83
+ AND (r.verdict IN ('affected', 'under_investigation') OR r.verdict IS NULL)`,
84
+ [dep.node_id]
85
+ );
86
+ for (const vuln of vulnRows) {
87
+ vulnerableDeps.push({
88
+ cveId: vuln.cve_id,
89
+ packageName: vuln.package_name ?? dep.package_name,
90
+ severity: vuln.severity_score,
91
+ epssScore: vuln.epss_score,
92
+ riskScore: vuln.risk_score,
93
+ verdict: vuln.verdict,
94
+ hopCount: dep.hop_count
95
+ });
96
+ }
97
+ }
98
+ const pathNodeNames = rawDb.all(
99
+ `WITH RECURSIVE reachable(node_id, depth) AS (
100
+ SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')
101
+ UNION
102
+ SELECT e.target, r.depth + 1
103
+ FROM edges e
104
+ JOIN reachable r ON e.source = r.node_id
105
+ WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')
106
+ )
107
+ SELECT DISTINCT n.name
108
+ FROM reachable r
109
+ JOIN nodes n ON n.id = r.node_id
110
+ WHERE n.name IS NOT NULL`,
111
+ [route.id]
112
+ );
113
+ const isAuthenticated = pathNodeNames.some((row) => {
114
+ const lowerName = (row.name ?? "").toLowerCase();
115
+ return AUTH_PATTERNS.some((pattern) => lowerName.includes(pattern));
116
+ });
117
+ const routeName = (route.name ?? "").toLowerCase();
118
+ let exposureLevel;
119
+ if (INTERNAL_ROUTE_PATTERNS.some((p) => routeName.includes(p))) {
120
+ exposureLevel = "internal";
121
+ } else if (isAuthenticated) {
122
+ exposureLevel = "authenticated";
123
+ } else if (PUBLIC_ROUTE_PATTERNS.some((p) => routeName.includes(p))) {
124
+ exposureLevel = "public";
125
+ } else {
126
+ exposureLevel = "unknown";
127
+ }
128
+ const affectedVulns = vulnerableDeps.filter((v) => v.verdict === "affected" || v.verdict === "under_investigation");
129
+ const riskScore = affectedVulns.reduce((max, v) => {
130
+ if (v.riskScore != null && v.riskScore > max) return v.riskScore;
131
+ return max;
132
+ }, 0);
133
+ entries.push({
134
+ route: route.name ?? route.id,
135
+ nodeId: route.id,
136
+ filePath: route.file_path ?? "",
137
+ isAuthenticated,
138
+ exposureLevel,
139
+ vulnerableDeps,
140
+ riskScore
141
+ });
142
+ }
143
+ const publicRoutes = entries.filter((e) => e.exposureLevel === "public").length;
144
+ const authenticatedRoutes = entries.filter(
145
+ (e) => e.exposureLevel === "authenticated" || e.exposureLevel === "internal"
146
+ ).length;
147
+ const routesWithVulns = entries.filter((e) => e.vulnerableDeps.length > 0).length;
148
+ const criticalPaths = entries.filter((e) => e.vulnerableDeps.length > 0).sort((a, b) => b.riskScore - a.riskScore);
149
+ const allRoutes = entries.sort((a, b) => b.riskScore - a.riskScore);
150
+ return {
151
+ totalRoutes: entries.length,
152
+ publicRoutes,
153
+ authenticatedRoutes,
154
+ routesWithVulns,
155
+ criticalPaths,
156
+ allRoutes
157
+ };
158
+ }
159
+ }
160
+ // Annotate the CommonJS export names for ESM import in node:
161
+ 0 && (module.exports = {
162
+ AttackSurfaceAnalyzer
163
+ });
164
+ //# sourceMappingURL=attack-surface.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/security/attack-surface.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph-Sec Attack Surface Analyzer\n *\n * Maps all route nodes in the knowledge graph to their reachable vulnerable\n * dependencies, computing exposure levels and risk scores per route.\n */\n\nimport type { GraphDatabase } from '../db/database';\n\n/** Auth-related name patterns for heuristic isAuthenticated detection. */\nconst AUTH_PATTERNS = [\n 'auth',\n 'authenticate',\n 'middleware',\n 'guard',\n 'protect',\n 'requirelogin',\n 'isloggedin',\n 'verifytoken',\n 'checkauth',\n 'ensureauth',\n] as const;\n\n/** Route path patterns that indicate a public-facing API. */\nconst PUBLIC_ROUTE_PATTERNS = ['/api/', '/v1/', '/v2/', '/v3/', '/graphql', '/rest/'];\n\n/** Route path patterns that indicate an internal/admin route. */\nconst INTERNAL_ROUTE_PATTERNS = ['/internal/', '/admin/'];\n\nexport interface AttackSurfaceEntry {\n route: string;\n nodeId: string;\n filePath: string;\n isAuthenticated: boolean;\n exposureLevel: 'public' | 'authenticated' | 'internal' | 'unknown';\n vulnerableDeps: Array<{\n cveId: string;\n packageName: string;\n severity: number | null;\n epssScore: number | null;\n riskScore: number | null;\n verdict: string | null;\n hopCount: number;\n }>;\n riskScore: number;\n}\n\nexport interface AttackSurfaceResult {\n totalRoutes: number;\n publicRoutes: number;\n authenticatedRoutes: number;\n routesWithVulns: number;\n criticalPaths: AttackSurfaceEntry[];\n allRoutes: AttackSurfaceEntry[];\n}\n\nexport class AttackSurfaceAnalyzer {\n constructor(private readonly db: GraphDatabase) {}\n\n async analyze(): Promise<AttackSurfaceResult> {\n const rawDb = this.db.getRawDb();\n\n // Step 1: Query all route nodes\n const routeRows: Array<{ id: string; name: string; file_path: string }> = rawDb.all(\n `SELECT id, name, file_path FROM nodes WHERE kind = 'route'`,\n );\n\n if (routeRows.length === 0) {\n return {\n totalRoutes: 0,\n publicRoutes: 0,\n authenticatedRoutes: 0,\n routesWithVulns: 0,\n criticalPaths: [],\n allRoutes: [],\n };\n }\n\n const entries: AttackSurfaceEntry[] = [];\n\n for (const route of routeRows) {\n // Step 2: BFS via SQL to find reachable dependency nodes (max 5 hops)\n const reachableDeps: Array<{\n node_id: string;\n package_name: string;\n hop_count: number;\n }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT d.node_id, d.package_name, MIN(r.depth) as hop_count\n FROM reachable r\n JOIN sec_dependencies d ON d.node_id = r.node_id\n GROUP BY d.node_id, d.package_name`,\n [route.id],\n );\n\n // Step 3: For each reachable dep, find affected/under_investigation vulns\n const vulnerableDeps: AttackSurfaceEntry['vulnerableDeps'] = [];\n\n for (const dep of reachableDeps) {\n const vulnRows: Array<{\n cve_id: string;\n package_name: string;\n severity_score: number | null;\n epss_score: number | null;\n risk_score: number | null;\n verdict: string | null;\n }> = rawDb.all(\n `SELECT v.cve_id, d.package_name, v.severity_score, v.epss_score, v.risk_score, r.verdict\n FROM sec_vulnerabilities v\n JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n JOIN sec_dependencies d ON d.node_id = e.source\n LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id\n WHERE d.node_id = ?\n AND (r.verdict IN ('affected', 'under_investigation') OR r.verdict IS NULL)`,\n [dep.node_id],\n );\n\n for (const vuln of vulnRows) {\n vulnerableDeps.push({\n cveId: vuln.cve_id,\n packageName: vuln.package_name ?? dep.package_name,\n severity: vuln.severity_score,\n epssScore: vuln.epss_score,\n riskScore: vuln.risk_score,\n verdict: vuln.verdict,\n hopCount: dep.hop_count,\n });\n }\n }\n\n // Step 4: Heuristic \u2014 isAuthenticated via path node names\n const pathNodeNames: Array<{ name: string }> = rawDb.all(\n `WITH RECURSIVE reachable(node_id, depth) AS (\n SELECT target, 1 FROM edges WHERE source = ? AND kind IN ('calls', 'imports', 'references')\n UNION\n SELECT e.target, r.depth + 1\n FROM edges e\n JOIN reachable r ON e.source = r.node_id\n WHERE r.depth < 5 AND e.kind IN ('calls', 'imports', 'references')\n )\n SELECT DISTINCT n.name\n FROM reachable r\n JOIN nodes n ON n.id = r.node_id\n WHERE n.name IS NOT NULL`,\n [route.id],\n );\n\n const isAuthenticated = pathNodeNames.some(row => {\n const lowerName = (row.name ?? '').toLowerCase();\n return AUTH_PATTERNS.some(pattern => lowerName.includes(pattern));\n });\n\n // Step 5: Determine exposure level\n const routeName = (route.name ?? '').toLowerCase();\n let exposureLevel: AttackSurfaceEntry['exposureLevel'];\n\n if (INTERNAL_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'internal';\n } else if (isAuthenticated) {\n exposureLevel = 'authenticated';\n } else if (PUBLIC_ROUTE_PATTERNS.some(p => routeName.includes(p))) {\n exposureLevel = 'public';\n } else {\n exposureLevel = 'unknown';\n }\n\n // Step 6: riskScore = max risk_score of reachable affected vulns\n const affectedVulns = vulnerableDeps.filter(v => v.verdict === 'affected' || v.verdict === 'under_investigation');\n const riskScore = affectedVulns.reduce((max, v) => {\n if (v.riskScore != null && v.riskScore > max) return v.riskScore;\n return max;\n }, 0);\n\n entries.push({\n route: route.name ?? route.id,\n nodeId: route.id,\n filePath: route.file_path ?? '',\n isAuthenticated,\n exposureLevel,\n vulnerableDeps,\n riskScore,\n });\n }\n\n // Compute summary stats\n const publicRoutes = entries.filter(e => e.exposureLevel === 'public').length;\n const authenticatedRoutes = entries.filter(\n e => e.exposureLevel === 'authenticated' || e.exposureLevel === 'internal',\n ).length;\n const routesWithVulns = entries.filter(e => e.vulnerableDeps.length > 0).length;\n\n // Critical paths: routes with affected/under_investigation vulns, sorted by riskScore desc\n const criticalPaths = entries\n .filter(e => e.vulnerableDeps.length > 0)\n .sort((a, b) => b.riskScore - a.riskScore);\n\n const allRoutes = entries.sort((a, b) => b.riskScore - a.riskScore);\n\n return {\n totalRoutes: entries.length,\n publicRoutes,\n authenticatedRoutes,\n routesWithVulns,\n criticalPaths,\n allRoutes,\n };\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var context_warnings_exports = {};
20
+ __export(context_warnings_exports, {
21
+ formatSecurityWarnings: () => formatSecurityWarnings,
22
+ getSecurityWarningsForNodes: () => getSecurityWarningsForNodes
23
+ });
24
+ module.exports = __toCommonJS(context_warnings_exports);
25
+ var import_fix_suggestions = require("./export/fix-suggestions");
26
+ function getSecurityWarningsForNodes(rawDb, nodeIds) {
27
+ if (nodeIds.length === 0) return [];
28
+ try {
29
+ const rows = rawDb.all(`
30
+ SELECT DISTINCT
31
+ v.cve_id,
32
+ v.severity_score,
33
+ v.epss_score,
34
+ v.epss_percentile,
35
+ v.fixed_version,
36
+ d.package_name,
37
+ d.ecosystem,
38
+ r.paths
39
+ FROM sec_reachability r
40
+ JOIN sec_vulnerabilities v ON v.node_id = r.vulnerability_node_id
41
+ JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'
42
+ JOIN sec_dependencies d ON d.node_id = e.source
43
+ WHERE r.verdict = 'affected'
44
+ ORDER BY v.epss_score DESC NULLS LAST, v.severity_score DESC NULLS LAST
45
+ `);
46
+ if (!rows || rows.length === 0) return [];
47
+ const nodeIdSet = new Set(nodeIds);
48
+ const warnings = [];
49
+ for (const row of rows) {
50
+ let paths = [];
51
+ try {
52
+ if (row.paths) {
53
+ paths = JSON.parse(row.paths);
54
+ }
55
+ } catch {
56
+ continue;
57
+ }
58
+ const matchingEntryPoints = [];
59
+ for (const p of paths) {
60
+ if (nodeIdSet.has(p.entryPoint)) {
61
+ matchingEntryPoints.push(p.entryPoint);
62
+ continue;
63
+ }
64
+ if (p.path && p.path.some((nodeId) => nodeIdSet.has(nodeId))) {
65
+ matchingEntryPoints.push(p.entryPoint);
66
+ }
67
+ }
68
+ if (matchingEntryPoints.length > 0) {
69
+ warnings.push({
70
+ cveId: row.cve_id,
71
+ severityScore: row.severity_score,
72
+ epssScore: row.epss_score,
73
+ epssPercentile: row.epss_percentile,
74
+ packageName: row.package_name,
75
+ ecosystem: row.ecosystem,
76
+ fixedVersion: row.fixed_version,
77
+ entryPoints: [...new Set(matchingEntryPoints)]
78
+ });
79
+ }
80
+ }
81
+ warnings.sort((a, b) => {
82
+ const epssA = a.epssScore ?? 0;
83
+ const epssB = b.epssScore ?? 0;
84
+ if (epssA !== epssB) return epssB - epssA;
85
+ return (b.severityScore ?? 0) - (a.severityScore ?? 0);
86
+ });
87
+ return warnings;
88
+ } catch {
89
+ return [];
90
+ }
91
+ }
92
+ function formatSecurityWarnings(warnings, nodeNames) {
93
+ if (warnings.length === 0) return "";
94
+ const MAX_SHOWN = 3;
95
+ const lines = ["", "## \u26A0 Security"];
96
+ const shown = warnings.slice(0, MAX_SHOWN);
97
+ for (const w of shown) {
98
+ const scoreParts = [];
99
+ if (w.severityScore !== null) scoreParts.push(`CVSS ${w.severityScore.toFixed(1)}`);
100
+ if (w.epssScore !== null) {
101
+ const pct = w.epssPercentile !== null ? ` / ${Math.round(w.epssPercentile * 100)}th%` : "";
102
+ scoreParts.push(`EPSS ${w.epssScore.toFixed(2)}${pct}`);
103
+ }
104
+ const scores = scoreParts.length > 0 ? ` (${scoreParts.join(", ")})` : "";
105
+ const entryPointNames = w.entryPoints.map((id) => nodeNames.get(id) ?? id).slice(0, 3);
106
+ const entryPointStr = entryPointNames.length > 0 ? ` \u2014 reaches via: ${entryPointNames.join(", ")}` : "";
107
+ lines.push(`- **${w.cveId}**${scores}: ${w.packageName} (${w.ecosystem})${entryPointStr}`);
108
+ const fix = (0, import_fix_suggestions.formatFixSuggestion)(w.ecosystem, w.packageName, w.fixedVersion);
109
+ if (fix) lines.push(` ${fix}`);
110
+ }
111
+ if (warnings.length > MAX_SHOWN) {
112
+ const remaining = warnings.length - MAX_SHOWN;
113
+ lines.push(`
114
+ ${remaining} more \u2014 use kirograph_vulns for full list`);
115
+ }
116
+ return lines.join("\n");
117
+ }
118
+ // Annotate the CommonJS export names for ESM import in node:
119
+ 0 && (module.exports = {
120
+ formatSecurityWarnings,
121
+ getSecurityWarningsForNodes
122
+ });
123
+ //# sourceMappingURL=context-warnings.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/security/context-warnings.ts"],
4
+ "sourcesContent": ["/**\n * Security Context Warnings\n *\n * Queries pre-computed reachability data to find vulnerabilities\n * reachable from symbols included in a context response.\n * Used by kirograph_context to append security warnings.\n */\n\nimport { formatFixSuggestion } from './export/fix-suggestions';\n\nexport interface SecurityWarning {\n cveId: string;\n severityScore: number | null;\n epssScore: number | null; // exploitation probability 0.0\u20131.0\n epssPercentile: number | null; // percentile rank among all CVEs\n packageName: string;\n ecosystem: string;\n fixedVersion: string | null;\n entryPoints: string[]; // node IDs of entry points that reach this vulnerability\n}\n\n/**\n * Query the pre-computed reachability data to find vulnerabilities\n * reachable from the given node IDs.\n *\n * This is a lightweight query joining sec_reachability + sec_vulnerabilities + sec_dependencies\n * where the reachability paths include any of the context nodes. No graph traversal needed\n * since reachability is pre-computed by the SecurityPipeline.\n *\n * @param rawDb - The raw SQLite database handle\n * @param nodeIds - Node IDs from the context response (entry points + related symbols)\n * @returns Array of SecurityWarning objects for affected vulnerabilities\n */\nexport function getSecurityWarningsForNodes(rawDb: any, nodeIds: string[]): SecurityWarning[] {\n if (nodeIds.length === 0) return [];\n\n try {\n // Query: find vulnerabilities with verdict 'affected' whose reachability paths\n // include any of the context node IDs.\n // The sec_reachability.paths field is a JSON array of ReachabilityPath objects,\n // each with an entryPoint and path array. We check if any entry point or path node\n // matches our context nodes.\n const rows = rawDb.all(`\n SELECT DISTINCT\n v.cve_id,\n v.severity_score,\n v.epss_score,\n v.epss_percentile,\n v.fixed_version,\n d.package_name,\n d.ecosystem,\n r.paths\n FROM sec_reachability r\n JOIN sec_vulnerabilities v ON v.node_id = r.vulnerability_node_id\n JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n JOIN sec_dependencies d ON d.node_id = e.source\n WHERE r.verdict = 'affected'\n ORDER BY v.epss_score DESC NULLS LAST, v.severity_score DESC NULLS LAST\n `) as Array<{\n cve_id: string;\n severity_score: number | null;\n epss_score: number | null;\n epss_percentile: number | null;\n fixed_version: string | null;\n package_name: string;\n ecosystem: string;\n paths: string | null;\n }>;\n\n if (!rows || rows.length === 0) return [];\n\n const nodeIdSet = new Set(nodeIds);\n const warnings: SecurityWarning[] = [];\n\n for (const row of rows) {\n // Parse the paths JSON to check if any context node is on a reachable path\n let paths: Array<{ entryPoint: string; path: string[] }> = [];\n try {\n if (row.paths) {\n paths = JSON.parse(row.paths);\n }\n } catch {\n continue;\n }\n\n // Find entry points from our context that reach this vulnerability\n const matchingEntryPoints: string[] = [];\n for (const p of paths) {\n // Check if the entry point is in our context nodes\n if (nodeIdSet.has(p.entryPoint)) {\n matchingEntryPoints.push(p.entryPoint);\n continue;\n }\n // Check if any node on the path is in our context nodes\n if (p.path && p.path.some(nodeId => nodeIdSet.has(nodeId))) {\n matchingEntryPoints.push(p.entryPoint);\n }\n }\n\n if (matchingEntryPoints.length > 0) {\n warnings.push({\n cveId: row.cve_id,\n severityScore: row.severity_score,\n epssScore: row.epss_score,\n epssPercentile: row.epss_percentile,\n packageName: row.package_name,\n ecosystem: row.ecosystem,\n fixedVersion: row.fixed_version,\n entryPoints: [...new Set(matchingEntryPoints)],\n });\n }\n }\n\n // Sort by risk: EPSS first (actual exploitation probability), then CVSS severity\n warnings.sort((a, b) => {\n const epssA = a.epssScore ?? 0;\n const epssB = b.epssScore ?? 0;\n if (epssA !== epssB) return epssB - epssA;\n return (b.severityScore ?? 0) - (a.severityScore ?? 0);\n });\n\n return warnings;\n } catch {\n // Security warnings are non-critical \u2014 don't fail context on query errors\n return [];\n }\n}\n\n/**\n * Format security warnings into a text section for the context output.\n * Shows max 3 vulnerabilities with a note about remaining ones.\n *\n * @param warnings - Array of SecurityWarning objects\n * @param nodeNames - Map of node IDs to human-readable names (for entry point display)\n * @returns Formatted string section, or empty string if no warnings\n */\nexport function formatSecurityWarnings(warnings: SecurityWarning[], nodeNames: Map<string, string>): string {\n if (warnings.length === 0) return '';\n\n const MAX_SHOWN = 3;\n const lines: string[] = ['', '## \u26A0 Security'];\n\n const shown = warnings.slice(0, MAX_SHOWN);\n for (const w of shown) {\n const scoreParts: string[] = [];\n if (w.severityScore !== null) scoreParts.push(`CVSS ${w.severityScore.toFixed(1)}`);\n if (w.epssScore !== null) {\n const pct = w.epssPercentile !== null ? ` / ${Math.round(w.epssPercentile * 100)}th%` : '';\n scoreParts.push(`EPSS ${w.epssScore.toFixed(2)}${pct}`);\n }\n const scores = scoreParts.length > 0 ? ` (${scoreParts.join(', ')})` : '';\n\n const entryPointNames = w.entryPoints\n .map(id => nodeNames.get(id) ?? id)\n .slice(0, 3);\n const entryPointStr = entryPointNames.length > 0\n ? ` \u2014 reaches via: ${entryPointNames.join(', ')}`\n : '';\n\n lines.push(`- **${w.cveId}**${scores}: ${w.packageName} (${w.ecosystem})${entryPointStr}`);\n\n const fix = formatFixSuggestion(w.ecosystem, w.packageName, w.fixedVersion);\n if (fix) lines.push(` ${fix}`);\n }\n\n if (warnings.length > MAX_SHOWN) {\n const remaining = warnings.length - MAX_SHOWN;\n lines.push(`\\n${remaining} more \u2014 use kirograph_vulns for full list`);\n }\n\n return lines.join('\\n');\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }