kirograph 0.17.0 → 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 (329) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +103 -1822
  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/attack-surface.js +157 -0
  10. package/dist/bin/commands/attack-surface.js.map +7 -0
  11. package/dist/bin/commands/benchmark.js +206 -0
  12. package/dist/bin/commands/benchmark.js.map +7 -0
  13. package/dist/bin/commands/budget.js +70 -0
  14. package/dist/bin/commands/budget.js.map +7 -0
  15. package/dist/bin/commands/communities.js +77 -0
  16. package/dist/bin/commands/communities.js.map +7 -0
  17. package/dist/bin/commands/dep-confusion.js +119 -0
  18. package/dist/bin/commands/dep-confusion.js.map +7 -0
  19. package/dist/bin/commands/export.js +304 -10
  20. package/dist/bin/commands/export.js.map +2 -2
  21. package/dist/bin/commands/flows.js +97 -0
  22. package/dist/bin/commands/flows.js.map +7 -0
  23. package/dist/bin/commands/help.js +382 -101
  24. package/dist/bin/commands/help.js.map +2 -2
  25. package/dist/bin/commands/install.js +90 -8
  26. package/dist/bin/commands/install.js.map +2 -2
  27. package/dist/bin/commands/licenses.js +201 -0
  28. package/dist/bin/commands/licenses.js.map +7 -0
  29. package/dist/bin/commands/reachability.js +160 -0
  30. package/dist/bin/commands/reachability.js.map +7 -0
  31. package/dist/bin/commands/read.js +100 -0
  32. package/dist/bin/commands/read.js.map +7 -0
  33. package/dist/bin/commands/refactor.js +116 -0
  34. package/dist/bin/commands/refactor.js.map +7 -0
  35. package/dist/bin/commands/remediation.js +133 -0
  36. package/dist/bin/commands/remediation.js.map +7 -0
  37. package/dist/bin/commands/sbom.js +76 -0
  38. package/dist/bin/commands/sbom.js.map +7 -0
  39. package/dist/bin/commands/security-ci-report.js +267 -0
  40. package/dist/bin/commands/security-ci-report.js.map +7 -0
  41. package/dist/bin/commands/security-export.js +1349 -0
  42. package/dist/bin/commands/security-export.js.map +7 -0
  43. package/dist/bin/commands/security-flows.js +126 -0
  44. package/dist/bin/commands/security-flows.js.map +7 -0
  45. package/dist/bin/commands/security-secrets.js +170 -0
  46. package/dist/bin/commands/security-secrets.js.map +7 -0
  47. package/dist/bin/commands/security.js +193 -0
  48. package/dist/bin/commands/security.js.map +7 -0
  49. package/dist/bin/commands/staleness.js +144 -0
  50. package/dist/bin/commands/staleness.js.map +7 -0
  51. package/dist/bin/commands/status.js +102 -2
  52. package/dist/bin/commands/status.js.map +2 -2
  53. package/dist/bin/commands/supply-chain.js +138 -0
  54. package/dist/bin/commands/supply-chain.js.map +7 -0
  55. package/dist/bin/commands/uninit.js +109 -60
  56. package/dist/bin/commands/uninit.js.map +2 -2
  57. package/dist/bin/commands/vex.js +76 -0
  58. package/dist/bin/commands/vex.js.map +7 -0
  59. package/dist/bin/commands/vuln-suppress.js +95 -0
  60. package/dist/bin/commands/vuln-suppress.js.map +7 -0
  61. package/dist/bin/commands/vulns.js +382 -0
  62. package/dist/bin/commands/vulns.js.map +7 -0
  63. package/dist/bin/installer/auto-detect.js +125 -0
  64. package/dist/bin/installer/auto-detect.js.map +7 -0
  65. package/dist/bin/installer/cli-agent.js +28 -5
  66. package/dist/bin/installer/cli-agent.js.map +2 -2
  67. package/dist/bin/installer/common.js +47 -0
  68. package/dist/bin/installer/common.js.map +2 -2
  69. package/dist/bin/installer/config-prompt.js +12 -1
  70. package/dist/bin/installer/config-prompt.js.map +2 -2
  71. package/dist/bin/installer/detect.js +309 -0
  72. package/dist/bin/installer/detect.js.map +7 -0
  73. package/dist/bin/installer/index.js +9 -1
  74. package/dist/bin/installer/index.js.map +2 -2
  75. package/dist/bin/installer/instructions.js +195 -3
  76. package/dist/bin/installer/instructions.js.map +2 -2
  77. package/dist/bin/installer/steering.js +407 -0
  78. package/dist/bin/installer/steering.js.map +2 -2
  79. package/dist/bin/installer/targets/aider.js +3 -3
  80. package/dist/bin/installer/targets/aider.js.map +2 -2
  81. package/dist/bin/installer/targets/amp.js +3 -3
  82. package/dist/bin/installer/targets/amp.js.map +2 -2
  83. package/dist/bin/installer/targets/antigravity.js +35 -6
  84. package/dist/bin/installer/targets/antigravity.js.map +2 -2
  85. package/dist/bin/installer/targets/augment.js +3 -3
  86. package/dist/bin/installer/targets/augment.js.map +2 -2
  87. package/dist/bin/installer/targets/claude.js +49 -5
  88. package/dist/bin/installer/targets/claude.js.map +2 -2
  89. package/dist/bin/installer/targets/cline.js +32 -6
  90. package/dist/bin/installer/targets/cline.js.map +2 -2
  91. package/dist/bin/installer/targets/codex.js +64 -12
  92. package/dist/bin/installer/targets/codex.js.map +2 -2
  93. package/dist/bin/installer/targets/continue.js +2 -2
  94. package/dist/bin/installer/targets/continue.js.map +2 -2
  95. package/dist/bin/installer/targets/copilot-cli.js +101 -0
  96. package/dist/bin/installer/targets/copilot-cli.js.map +7 -0
  97. package/dist/bin/installer/targets/copilot.js +31 -5
  98. package/dist/bin/installer/targets/copilot.js.map +2 -2
  99. package/dist/bin/installer/targets/cursor.js +4 -4
  100. package/dist/bin/installer/targets/cursor.js.map +2 -2
  101. package/dist/bin/installer/targets/devin.js +2 -2
  102. package/dist/bin/installer/targets/devin.js.map +2 -2
  103. package/dist/bin/installer/targets/gemini-cli.js +2 -2
  104. package/dist/bin/installer/targets/gemini-cli.js.map +2 -2
  105. package/dist/bin/installer/targets/generic.js +2 -14
  106. package/dist/bin/installer/targets/generic.js.map +2 -2
  107. package/dist/bin/installer/targets/goose.js +3 -3
  108. package/dist/bin/installer/targets/goose.js.map +2 -2
  109. package/dist/bin/installer/targets/index.js +250 -0
  110. package/dist/bin/installer/targets/index.js.map +2 -2
  111. package/dist/bin/installer/targets/junie.js +2 -2
  112. package/dist/bin/installer/targets/junie.js.map +2 -2
  113. package/dist/bin/installer/targets/kilo.js +2 -2
  114. package/dist/bin/installer/targets/kilo.js.map +2 -2
  115. package/dist/bin/installer/targets/kiro.js +3 -3
  116. package/dist/bin/installer/targets/kiro.js.map +2 -2
  117. package/dist/bin/installer/targets/opencode.js +2 -2
  118. package/dist/bin/installer/targets/opencode.js.map +2 -2
  119. package/dist/bin/installer/targets/openhands.js +3 -3
  120. package/dist/bin/installer/targets/openhands.js.map +2 -2
  121. package/dist/bin/installer/targets/qoder.js +91 -0
  122. package/dist/bin/installer/targets/qoder.js.map +7 -0
  123. package/dist/bin/installer/targets/qwen.js +96 -0
  124. package/dist/bin/installer/targets/qwen.js.map +7 -0
  125. package/dist/bin/installer/targets/replit.js +3 -3
  126. package/dist/bin/installer/targets/replit.js.map +2 -2
  127. package/dist/bin/installer/targets/roo.js +2 -2
  128. package/dist/bin/installer/targets/roo.js.map +2 -2
  129. package/dist/bin/installer/targets/tabnine.js +3 -3
  130. package/dist/bin/installer/targets/tabnine.js.map +2 -2
  131. package/dist/bin/installer/targets/trae.js +5 -5
  132. package/dist/bin/installer/targets/trae.js.map +2 -2
  133. package/dist/bin/installer/targets/warp.js +2 -2
  134. package/dist/bin/installer/targets/warp.js.map +2 -2
  135. package/dist/bin/installer/targets/windsurf.js +35 -6
  136. package/dist/bin/installer/targets/windsurf.js.map +2 -2
  137. package/dist/bin/kirograph.js +72 -6
  138. package/dist/bin/kirograph.js.map +3 -3
  139. package/dist/compression/tracker.js +80 -0
  140. package/dist/compression/tracker.js.map +2 -2
  141. package/dist/config.js +90 -3
  142. package/dist/config.js.map +2 -2
  143. package/dist/core/pipeline.js +36 -2
  144. package/dist/core/pipeline.js.map +2 -2
  145. package/dist/db/database.js +56 -5
  146. package/dist/db/database.js.map +2 -2
  147. package/dist/db/memory-schema.sql +5 -1
  148. package/dist/db/schema.sql +3 -1
  149. package/dist/db/security-schema.sql +72 -0
  150. package/dist/extraction/extractor.js +81 -0
  151. package/dist/extraction/extractor.js.map +2 -2
  152. package/dist/extraction/grammars.js +32 -8
  153. package/dist/extraction/grammars.js.map +2 -2
  154. package/dist/extraction/languages.js +43 -1
  155. package/dist/extraction/languages.js.map +2 -2
  156. package/dist/extraction/notebook.js +300 -0
  157. package/dist/extraction/notebook.js.map +7 -0
  158. package/dist/extraction/wasm/tree-sitter-astro.wasm +0 -0
  159. package/dist/extraction/wasm/tree-sitter-gdscript.wasm +0 -0
  160. package/dist/extraction/wasm/tree-sitter-julia.wasm +0 -0
  161. package/dist/extraction/wasm/tree-sitter-nix.wasm +0 -0
  162. package/dist/extraction/wasm/tree-sitter-perl.wasm +0 -0
  163. package/dist/extraction/wasm/tree-sitter-powershell.wasm +0 -0
  164. package/dist/extraction/wasm/tree-sitter-r.wasm +0 -0
  165. package/dist/extraction/wasm/tree-sitter-sql.wasm +0 -0
  166. package/dist/extraction/wasm/tree-sitter-verilog.wasm +0 -0
  167. package/dist/frameworks/flutter.js +130 -0
  168. package/dist/frameworks/flutter.js.map +7 -0
  169. package/dist/frameworks/index.js +7 -1
  170. package/dist/frameworks/index.js.map +3 -3
  171. package/dist/graph/communities.js +317 -0
  172. package/dist/graph/communities.js.map +7 -0
  173. package/dist/graph/flows.js +138 -0
  174. package/dist/graph/flows.js.map +7 -0
  175. package/dist/graph/refactor.js +155 -0
  176. package/dist/graph/refactor.js.map +7 -0
  177. package/dist/index.js +1 -1
  178. package/dist/index.js.map +2 -2
  179. package/dist/mcp/cache.js +172 -0
  180. package/dist/mcp/cache.js.map +7 -0
  181. package/dist/mcp/read-modes.js +295 -0
  182. package/dist/mcp/read-modes.js.map +7 -0
  183. package/dist/mcp/server.js +2 -1
  184. package/dist/mcp/server.js.map +2 -2
  185. package/dist/mcp/tool-names.js +21 -1
  186. package/dist/mcp/tool-names.js.map +2 -2
  187. package/dist/mcp/tools.js +1160 -1
  188. package/dist/mcp/tools.js.map +3 -3
  189. package/dist/memory/database.js +32 -2
  190. package/dist/memory/database.js.map +2 -2
  191. package/dist/memory/types.js.map +1 -1
  192. package/dist/resolution/bridges/android-rn.js +298 -0
  193. package/dist/resolution/bridges/android-rn.js.map +7 -0
  194. package/dist/resolution/bridges/expo-modules.js +155 -0
  195. package/dist/resolution/bridges/expo-modules.js.map +7 -0
  196. package/dist/resolution/bridges/flutter-channel.js +385 -0
  197. package/dist/resolution/bridges/flutter-channel.js.map +7 -0
  198. package/dist/resolution/bridges/index.js +80 -0
  199. package/dist/resolution/bridges/index.js.map +7 -0
  200. package/dist/resolution/bridges/native-events.js +188 -0
  201. package/dist/resolution/bridges/native-events.js.map +7 -0
  202. package/dist/resolution/bridges/native-views.js +244 -0
  203. package/dist/resolution/bridges/native-views.js.map +7 -0
  204. package/dist/resolution/bridges/react-native.js +161 -0
  205. package/dist/resolution/bridges/react-native.js.map +7 -0
  206. package/dist/resolution/bridges/swift-objc.js +227 -0
  207. package/dist/resolution/bridges/swift-objc.js.map +7 -0
  208. package/dist/resolution/bridges/turbomodules.js +216 -0
  209. package/dist/resolution/bridges/turbomodules.js.map +7 -0
  210. package/dist/resolution/index.js +61 -2
  211. package/dist/resolution/index.js.map +2 -2
  212. package/dist/security/attack-surface.js +164 -0
  213. package/dist/security/attack-surface.js.map +7 -0
  214. package/dist/security/context-warnings.js +123 -0
  215. package/dist/security/context-warnings.js.map +7 -0
  216. package/dist/security/context-warnings.test.js +300 -0
  217. package/dist/security/context-warnings.test.js.map +7 -0
  218. package/dist/security/data-flows.js +228 -0
  219. package/dist/security/data-flows.js.map +7 -0
  220. package/dist/security/dep-confusion.js +255 -0
  221. package/dist/security/dep-confusion.js.map +7 -0
  222. package/dist/security/errors.js +51 -0
  223. package/dist/security/errors.js.map +7 -0
  224. package/dist/security/export/fix-suggestions.js +58 -0
  225. package/dist/security/export/fix-suggestions.js.map +7 -0
  226. package/dist/security/export/fix-suggestions.test.js +74 -0
  227. package/dist/security/export/fix-suggestions.test.js.map +7 -0
  228. package/dist/security/export/sbom.js +230 -0
  229. package/dist/security/export/sbom.js.map +7 -0
  230. package/dist/security/export/sbom.test.js +288 -0
  231. package/dist/security/export/sbom.test.js.map +7 -0
  232. package/dist/security/export/serialization.js +142 -0
  233. package/dist/security/export/serialization.js.map +7 -0
  234. package/dist/security/export/serialization.test.js +310 -0
  235. package/dist/security/export/serialization.test.js.map +7 -0
  236. package/dist/security/export/vex.js +220 -0
  237. package/dist/security/export/vex.js.map +7 -0
  238. package/dist/security/export/vex.test.js +278 -0
  239. package/dist/security/export/vex.test.js.map +7 -0
  240. package/dist/security/index.js +67 -0
  241. package/dist/security/index.js.map +7 -0
  242. package/dist/security/integrator-transitives.test.js +359 -0
  243. package/dist/security/integrator-transitives.test.js.map +7 -0
  244. package/dist/security/integrator.js +491 -0
  245. package/dist/security/integrator.js.map +7 -0
  246. package/dist/security/integrator.test.js +237 -0
  247. package/dist/security/integrator.test.js.map +7 -0
  248. package/dist/security/license.js +70 -0
  249. package/dist/security/license.js.map +7 -0
  250. package/dist/security/manifest/adapter.js +243 -0
  251. package/dist/security/manifest/adapter.js.map +7 -0
  252. package/dist/security/manifest/adapter.test.js +272 -0
  253. package/dist/security/manifest/adapter.test.js.map +7 -0
  254. package/dist/security/manifest/parser.js +376 -0
  255. package/dist/security/manifest/parser.js.map +7 -0
  256. package/dist/security/manifest/parser.test.js +110 -0
  257. package/dist/security/manifest/parser.test.js.map +7 -0
  258. package/dist/security/manifest/plugins/cargo.js +233 -0
  259. package/dist/security/manifest/plugins/cargo.js.map +7 -0
  260. package/dist/security/manifest/plugins/cargo.test.js +304 -0
  261. package/dist/security/manifest/plugins/cargo.test.js.map +7 -0
  262. package/dist/security/manifest/plugins/composer.js +152 -0
  263. package/dist/security/manifest/plugins/composer.js.map +7 -0
  264. package/dist/security/manifest/plugins/go.js +146 -0
  265. package/dist/security/manifest/plugins/go.js.map +7 -0
  266. package/dist/security/manifest/plugins/go.test.js +341 -0
  267. package/dist/security/manifest/plugins/go.test.js.map +7 -0
  268. package/dist/security/manifest/plugins/gradle.js +159 -0
  269. package/dist/security/manifest/plugins/gradle.js.map +7 -0
  270. package/dist/security/manifest/plugins/hex.js +159 -0
  271. package/dist/security/manifest/plugins/hex.js.map +7 -0
  272. package/dist/security/manifest/plugins/maven.js +128 -0
  273. package/dist/security/manifest/plugins/maven.js.map +7 -0
  274. package/dist/security/manifest/plugins/maven.test.js +389 -0
  275. package/dist/security/manifest/plugins/maven.test.js.map +7 -0
  276. package/dist/security/manifest/plugins/npm.js +284 -0
  277. package/dist/security/manifest/plugins/npm.js.map +7 -0
  278. package/dist/security/manifest/plugins/npm.test.js +298 -0
  279. package/dist/security/manifest/plugins/npm.test.js.map +7 -0
  280. package/dist/security/manifest/plugins/nuget.js +186 -0
  281. package/dist/security/manifest/plugins/nuget.js.map +7 -0
  282. package/dist/security/manifest/plugins/pip.js +123 -0
  283. package/dist/security/manifest/plugins/pip.js.map +7 -0
  284. package/dist/security/manifest/plugins/pip.test.js +208 -0
  285. package/dist/security/manifest/plugins/pip.test.js.map +7 -0
  286. package/dist/security/manifest/plugins/pubspec.js +212 -0
  287. package/dist/security/manifest/plugins/pubspec.js.map +7 -0
  288. package/dist/security/manifest/plugins/pyproject.js +261 -0
  289. package/dist/security/manifest/plugins/pyproject.js.map +7 -0
  290. package/dist/security/manifest/plugins/rubygems.js +185 -0
  291. package/dist/security/manifest/plugins/rubygems.js.map +7 -0
  292. package/dist/security/manifest/plugins/swift.js +200 -0
  293. package/dist/security/manifest/plugins/swift.js.map +7 -0
  294. package/dist/security/owasp.js +104 -0
  295. package/dist/security/owasp.js.map +7 -0
  296. package/dist/security/pipeline.js +125 -0
  297. package/dist/security/pipeline.js.map +7 -0
  298. package/dist/security/reachability.js +276 -0
  299. package/dist/security/reachability.js.map +7 -0
  300. package/dist/security/reachability.test.js +394 -0
  301. package/dist/security/reachability.test.js.map +7 -0
  302. package/dist/security/remediation.js +126 -0
  303. package/dist/security/remediation.js.map +7 -0
  304. package/dist/security/secrets.js +176 -0
  305. package/dist/security/secrets.js.map +7 -0
  306. package/dist/security/staleness.js +231 -0
  307. package/dist/security/staleness.js.map +7 -0
  308. package/dist/security/supply-chain.js +301 -0
  309. package/dist/security/supply-chain.js.map +7 -0
  310. package/dist/security/suppressions.js +106 -0
  311. package/dist/security/suppressions.js.map +7 -0
  312. package/dist/security/types.js +17 -0
  313. package/dist/security/types.js.map +7 -0
  314. package/dist/security/vuln/client.js +355 -0
  315. package/dist/security/vuln/client.js.map +7 -0
  316. package/dist/security/vuln/client.test.js +288 -0
  317. package/dist/security/vuln/client.test.js.map +7 -0
  318. package/dist/security/vuln/epss-client.js +95 -0
  319. package/dist/security/vuln/epss-client.js.map +7 -0
  320. package/dist/security/vuln/index.js +29 -0
  321. package/dist/security/vuln/index.js.map +7 -0
  322. package/dist/security/vuln/osv-adapter.js +321 -0
  323. package/dist/security/vuln/osv-adapter.js.map +7 -0
  324. package/dist/security/vuln/osv-adapter.test.js +391 -0
  325. package/dist/security/vuln/osv-adapter.test.js.map +7 -0
  326. package/dist/security/vuln/types.js +17 -0
  327. package/dist/security/vuln/types.js.map +7 -0
  328. package/dist/types.js.map +2 -2
  329. package/package.json +2 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/frameworks/index.ts"],
4
- "sourcesContent": ["/**\n * Framework Resolver Registry\n *\n * Mirrors CodeGraph src/resolution/frameworks/index.ts\n * Manages framework-specific resolvers and detection.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { logDebug, logWarn } from '../errors';\nimport { updateConfig } from '../config';\nimport type { Node } from '../types';\nimport type { GraphDatabase } from '../db/database';\nimport type { FrameworkResolver, ResolutionContext } from './types';\n\n// Re-export types\nexport type { FrameworkResolver, ResolutionContext, UnresolvedRef, ResolvedRef } from './types';\n\n// Re-export individual resolvers\nexport { reactResolver } from './react';\nexport { svelteResolver } from './svelte';\nexport { expressResolver } from './express';\nexport { djangoResolver, flaskResolver, fastapiResolver } from './python';\nexport { railsResolver } from './ruby';\nexport { springResolver } from './java';\nexport { goResolver } from './go';\nexport { rustResolver } from './rust';\nexport { aspnetResolver } from './csharp';\nexport { swiftUIResolver, uikitResolver, vaporResolver } from './swift';\nexport { laravelResolver, FACADE_MAPPINGS } from './laravel';\nexport { phoenixResolver } from './elixir';\nexport { playResolver } from './scala';\nexport { nuxtResolver, vueResolver } from './vue';\nexport { solidityResolver } from './solidity';\nexport { sstResolver, cdkResolver, serverlessResolver, samResolver } from './iac';\nexport { terraformResolver } from './terraform';\nexport { pulumiResolver } from './pulumi';\nexport { cloudformationResolver } from './cloudformation';\nexport { kubernetesResolver } from './kubernetes';\nexport { dockerComposeResolver } from './docker';\nexport { ansibleResolver } from './ansible';\nexport { angularResolver } from './angular';\nexport { amplifyResolver } from './amplify';\n\n// \u2500\u2500 Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nimport { reactResolver } from './react';\nimport { svelteResolver } from './svelte';\nimport { expressResolver } from './express';\nimport { djangoResolver, flaskResolver, fastapiResolver } from './python';\nimport { railsResolver } from './ruby';\nimport { springResolver } from './java';\nimport { goResolver } from './go';\nimport { rustResolver } from './rust';\nimport { aspnetResolver } from './csharp';\nimport { swiftUIResolver, uikitResolver, vaporResolver } from './swift';\nimport { laravelResolver } from './laravel';\nimport { phoenixResolver } from './elixir';\nimport { playResolver } from './scala';\nimport { nuxtResolver, vueResolver } from './vue';\nimport { solidityResolver } from './solidity';\nimport { sstResolver, cdkResolver, serverlessResolver, samResolver } from './iac';\nimport { terraformResolver } from './terraform';\nimport { pulumiResolver } from './pulumi';\nimport { cloudformationResolver } from './cloudformation';\nimport { kubernetesResolver } from './kubernetes';\nimport { dockerComposeResolver } from './docker';\nimport { ansibleResolver } from './ansible';\nimport { angularResolver } from './angular';\nimport { amplifyResolver } from './amplify';\n\nconst FRAMEWORK_RESOLVERS: FrameworkResolver[] = [\n // PHP\n laravelResolver,\n // JavaScript / TypeScript\n expressResolver,\n reactResolver,\n svelteResolver,\n angularResolver,\n // Vue / Nuxt\n nuxtResolver,\n vueResolver,\n // Python\n djangoResolver,\n flaskResolver,\n fastapiResolver,\n // Ruby\n railsResolver,\n // Java\n springResolver,\n // Go\n goResolver,\n // Rust\n rustResolver,\n // C#\n aspnetResolver,\n // Swift\n swiftUIResolver,\n uikitResolver,\n vaporResolver,\n // Elixir\n phoenixResolver,\n // Scala\n playResolver,\n // Solidity\n solidityResolver,\n // Infrastructure as Code\n sstResolver,\n cdkResolver,\n serverlessResolver,\n samResolver,\n terraformResolver,\n pulumiResolver,\n cloudformationResolver,\n amplifyResolver,\n // Containers & Orchestration\n kubernetesResolver,\n dockerComposeResolver,\n // Configuration Management\n ansibleResolver,\n];\n\nexport function getAllFrameworkResolvers(): FrameworkResolver[] {\n return FRAMEWORK_RESOLVERS;\n}\n\nexport function getFrameworkResolver(name: string): FrameworkResolver | undefined {\n return FRAMEWORK_RESOLVERS.find(r => r.name === name);\n}\n\nexport function registerFrameworkResolver(resolver: FrameworkResolver): void {\n const index = FRAMEWORK_RESOLVERS.findIndex(r => r.name === resolver.name);\n if (index !== -1) FRAMEWORK_RESOLVERS.splice(index, 1);\n FRAMEWORK_RESOLVERS.push(resolver);\n}\n\n// \u2500\u2500 Context builder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction buildResolutionContext(projectRoot: string, db: GraphDatabase): ResolutionContext {\n const fileCache = new Map<string, string | null>();\n const nodeCache = new Map<string, Node[]>();\n\n return {\n getNodesInFile(filePath: string): Node[] {\n if (!nodeCache.has(filePath)) {\n nodeCache.set(filePath, db.getNodesByFile(filePath));\n }\n return nodeCache.get(filePath)!;\n },\n getNodesByName(name: string): Node[] {\n return db.findNodesByExactName(name);\n },\n getNodesByKind(kind: Node['kind']): Node[] {\n return db.getNodesByKind(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 => f.path);\n },\n };\n}\n\n// \u2500\u2500 detectFrameworks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Detect which frameworks are used in a project.\n * Mirrors CodeGraph detectFrameworks() \u2014 uses ResolutionContext for file access.\n * Records detected framework names in config via updateConfig().\n */\nexport async function detectFrameworks(projectRoot: string, db?: GraphDatabase): Promise<FrameworkResolver[]> {\n // If no db provided, fall back to package.json-only detection\n if (!db) {\n return detectFromPackageJson(projectRoot);\n }\n\n const context = buildResolutionContext(projectRoot, db);\n const detected: FrameworkResolver[] = [];\n\n for (const resolver of FRAMEWORK_RESOLVERS) {\n try {\n if (resolver.detect(context)) {\n logDebug(`detectFrameworks: detected ${resolver.name}`);\n detected.push(resolver);\n }\n } catch (err) {\n logWarn(`detectFrameworks: error detecting ${resolver.name}`, { error: String(err) });\n }\n }\n\n if (detected.length > 0) {\n await updateConfig(projectRoot, { frameworkHints: detected.map(f => f.name) });\n }\n\n return detected;\n}\n\n/**\n * Lightweight fallback: detect frameworks from package.json only (no DB needed).\n */\nasync function detectFromPackageJson(projectRoot: string): Promise<FrameworkResolver[]> {\n const pkgPath = path.join(projectRoot, 'package.json');\n if (!fs.existsSync(pkgPath)) return [];\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as Record<string, unknown>;\n } catch {\n return [];\n }\n\n const deps: Record<string, string> = {\n ...((pkg.dependencies as Record<string, string>) ?? {}),\n ...((pkg.devDependencies as Record<string, string>) ?? {}),\n };\n\n const PACKAGE_TO_RESOLVER: Record<string, string> = {\n react: 'react', next: 'react', 'react-native': 'react',\n svelte: 'svelte', '@sveltejs/kit': 'svelte',\n express: 'express', fastify: 'express', koa: 'express',\n };\n\n const detectedNames = new Set<string>();\n const detected: FrameworkResolver[] = [];\n\n for (const [pkg, resolverName] of Object.entries(PACKAGE_TO_RESOLVER)) {\n if (Object.prototype.hasOwnProperty.call(deps, pkg) && !detectedNames.has(resolverName)) {\n const resolver = getFrameworkResolver(resolverName);\n if (resolver) {\n detectedNames.add(resolverName);\n detected.push(resolver);\n }\n }\n }\n\n if (detected.length > 0) {\n await updateConfig(projectRoot, { frameworkHints: detected.map(f => f.name) });\n }\n\n return detected;\n}\n"],
5
- "mappings": "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",
6
- "names": ["import_react", "import_svelte", "import_express", "import_python", "import_ruby", "import_java", "import_go", "import_rust", "import_csharp", "import_swift", "import_laravel", "import_elixir", "import_scala", "import_vue", "import_solidity", "import_iac", "import_terraform", "import_pulumi", "import_cloudformation", "import_kubernetes", "import_docker", "import_ansible", "import_angular", "import_amplify", "pkg"]
4
+ "sourcesContent": ["/**\n * Framework Resolver Registry\n *\n * Mirrors CodeGraph src/resolution/frameworks/index.ts\n * Manages framework-specific resolvers and detection.\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { logDebug, logWarn } from '../errors';\nimport { updateConfig } from '../config';\nimport type { Node } from '../types';\nimport type { GraphDatabase } from '../db/database';\nimport type { FrameworkResolver, ResolutionContext } from './types';\n\n// Re-export types\nexport type { FrameworkResolver, ResolutionContext, UnresolvedRef, ResolvedRef } from './types';\n\n// Re-export individual resolvers\nexport { reactResolver } from './react';\nexport { svelteResolver } from './svelte';\nexport { expressResolver } from './express';\nexport { djangoResolver, flaskResolver, fastapiResolver } from './python';\nexport { railsResolver } from './ruby';\nexport { springResolver } from './java';\nexport { goResolver } from './go';\nexport { rustResolver } from './rust';\nexport { aspnetResolver } from './csharp';\nexport { swiftUIResolver, uikitResolver, vaporResolver } from './swift';\nexport { laravelResolver, FACADE_MAPPINGS } from './laravel';\nexport { phoenixResolver } from './elixir';\nexport { playResolver } from './scala';\nexport { nuxtResolver, vueResolver } from './vue';\nexport { solidityResolver } from './solidity';\nexport { sstResolver, cdkResolver, serverlessResolver, samResolver } from './iac';\nexport { terraformResolver } from './terraform';\nexport { pulumiResolver } from './pulumi';\nexport { cloudformationResolver } from './cloudformation';\nexport { kubernetesResolver } from './kubernetes';\nexport { dockerComposeResolver } from './docker';\nexport { ansibleResolver } from './ansible';\nexport { angularResolver } from './angular';\nexport { amplifyResolver } from './amplify';\nexport { flutterResolver } from './flutter';\n\n// \u2500\u2500 Registry \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nimport { reactResolver } from './react';\nimport { svelteResolver } from './svelte';\nimport { expressResolver } from './express';\nimport { djangoResolver, flaskResolver, fastapiResolver } from './python';\nimport { railsResolver } from './ruby';\nimport { springResolver } from './java';\nimport { goResolver } from './go';\nimport { rustResolver } from './rust';\nimport { aspnetResolver } from './csharp';\nimport { swiftUIResolver, uikitResolver, vaporResolver } from './swift';\nimport { laravelResolver } from './laravel';\nimport { phoenixResolver } from './elixir';\nimport { playResolver } from './scala';\nimport { nuxtResolver, vueResolver } from './vue';\nimport { solidityResolver } from './solidity';\nimport { sstResolver, cdkResolver, serverlessResolver, samResolver } from './iac';\nimport { terraformResolver } from './terraform';\nimport { pulumiResolver } from './pulumi';\nimport { cloudformationResolver } from './cloudformation';\nimport { kubernetesResolver } from './kubernetes';\nimport { dockerComposeResolver } from './docker';\nimport { ansibleResolver } from './ansible';\nimport { angularResolver } from './angular';\nimport { amplifyResolver } from './amplify';\nimport { flutterResolver } from './flutter';\n\nconst FRAMEWORK_RESOLVERS: FrameworkResolver[] = [\n // PHP\n laravelResolver,\n // JavaScript / TypeScript\n expressResolver,\n reactResolver,\n svelteResolver,\n angularResolver,\n // Vue / Nuxt\n nuxtResolver,\n vueResolver,\n // Python\n djangoResolver,\n flaskResolver,\n fastapiResolver,\n // Ruby\n railsResolver,\n // Java\n springResolver,\n // Go\n goResolver,\n // Rust\n rustResolver,\n // C#\n aspnetResolver,\n // Swift\n swiftUIResolver,\n uikitResolver,\n vaporResolver,\n // Elixir\n phoenixResolver,\n // Scala\n playResolver,\n // Solidity\n solidityResolver,\n // Infrastructure as Code\n sstResolver,\n cdkResolver,\n serverlessResolver,\n samResolver,\n terraformResolver,\n pulumiResolver,\n cloudformationResolver,\n amplifyResolver,\n // Containers & Orchestration\n kubernetesResolver,\n dockerComposeResolver,\n // Configuration Management\n ansibleResolver,\n // Dart / Flutter\n flutterResolver,\n];\n\nexport function getAllFrameworkResolvers(): FrameworkResolver[] {\n return FRAMEWORK_RESOLVERS;\n}\n\nexport function getFrameworkResolver(name: string): FrameworkResolver | undefined {\n return FRAMEWORK_RESOLVERS.find(r => r.name === name);\n}\n\nexport function registerFrameworkResolver(resolver: FrameworkResolver): void {\n const index = FRAMEWORK_RESOLVERS.findIndex(r => r.name === resolver.name);\n if (index !== -1) FRAMEWORK_RESOLVERS.splice(index, 1);\n FRAMEWORK_RESOLVERS.push(resolver);\n}\n\n// \u2500\u2500 Context builder \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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\nfunction buildResolutionContext(projectRoot: string, db: GraphDatabase): ResolutionContext {\n const fileCache = new Map<string, string | null>();\n const nodeCache = new Map<string, Node[]>();\n\n return {\n getNodesInFile(filePath: string): Node[] {\n if (!nodeCache.has(filePath)) {\n nodeCache.set(filePath, db.getNodesByFile(filePath));\n }\n return nodeCache.get(filePath)!;\n },\n getNodesByName(name: string): Node[] {\n return db.findNodesByExactName(name);\n },\n getNodesByKind(kind: Node['kind']): Node[] {\n return db.getNodesByKind(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 => f.path);\n },\n };\n}\n\n// \u2500\u2500 detectFrameworks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 * Detect which frameworks are used in a project.\n * Mirrors CodeGraph detectFrameworks() \u2014 uses ResolutionContext for file access.\n * Records detected framework names in config via updateConfig().\n */\nexport async function detectFrameworks(projectRoot: string, db?: GraphDatabase): Promise<FrameworkResolver[]> {\n // If no db provided, fall back to package.json-only detection\n if (!db) {\n return detectFromPackageJson(projectRoot);\n }\n\n const context = buildResolutionContext(projectRoot, db);\n const detected: FrameworkResolver[] = [];\n\n for (const resolver of FRAMEWORK_RESOLVERS) {\n try {\n if (resolver.detect(context)) {\n logDebug(`detectFrameworks: detected ${resolver.name}`);\n detected.push(resolver);\n }\n } catch (err) {\n logWarn(`detectFrameworks: error detecting ${resolver.name}`, { error: String(err) });\n }\n }\n\n if (detected.length > 0) {\n await updateConfig(projectRoot, { frameworkHints: detected.map(f => f.name) });\n }\n\n return detected;\n}\n\n/**\n * Lightweight fallback: detect frameworks from package.json only (no DB needed).\n */\nasync function detectFromPackageJson(projectRoot: string): Promise<FrameworkResolver[]> {\n const pkgPath = path.join(projectRoot, 'package.json');\n if (!fs.existsSync(pkgPath)) return [];\n\n let pkg: Record<string, unknown>;\n try {\n pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as Record<string, unknown>;\n } catch {\n return [];\n }\n\n const deps: Record<string, string> = {\n ...((pkg.dependencies as Record<string, string>) ?? {}),\n ...((pkg.devDependencies as Record<string, string>) ?? {}),\n };\n\n const PACKAGE_TO_RESOLVER: Record<string, string> = {\n react: 'react', next: 'react', 'react-native': 'react',\n svelte: 'svelte', '@sveltejs/kit': 'svelte',\n express: 'express', fastify: 'express', koa: 'express',\n };\n\n const detectedNames = new Set<string>();\n const detected: FrameworkResolver[] = [];\n\n for (const [pkg, resolverName] of Object.entries(PACKAGE_TO_RESOLVER)) {\n if (Object.prototype.hasOwnProperty.call(deps, pkg) && !detectedNames.has(resolverName)) {\n const resolver = getFrameworkResolver(resolverName);\n if (resolver) {\n detectedNames.add(resolverName);\n detected.push(resolver);\n }\n }\n }\n\n if (detected.length > 0) {\n await updateConfig(projectRoot, { frameworkHints: detected.map(f => f.name) });\n }\n\n return detected;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_react", "import_svelte", "import_express", "import_python", "import_ruby", "import_java", "import_go", "import_rust", "import_csharp", "import_swift", "import_laravel", "import_elixir", "import_scala", "import_vue", "import_solidity", "import_iac", "import_terraform", "import_pulumi", "import_cloudformation", "import_kubernetes", "import_docker", "import_ansible", "import_angular", "import_amplify", "import_flutter", "pkg"]
7
7
  }
@@ -0,0 +1,317 @@
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 communities_exports = {};
20
+ __export(communities_exports, {
21
+ detectCommunities: () => detectCommunities
22
+ });
23
+ module.exports = __toCommonJS(communities_exports);
24
+ function buildAdjacency(db) {
25
+ const rawDb = db.getRawDb();
26
+ const edges = rawDb.all(
27
+ `SELECT source, target FROM edges WHERE kind != 'contains'`
28
+ );
29
+ const nodes = /* @__PURE__ */ new Map();
30
+ const adj = /* @__PURE__ */ new Map();
31
+ let totalWeight = 0;
32
+ for (const e of edges) {
33
+ if (!nodes.has(e.source)) nodes.set(e.source, { id: e.source, community: 0, degree: 0 });
34
+ if (!nodes.has(e.target)) nodes.set(e.target, { id: e.target, community: 0, degree: 0 });
35
+ if (!adj.has(e.source)) adj.set(e.source, /* @__PURE__ */ new Map());
36
+ if (!adj.has(e.target)) adj.set(e.target, /* @__PURE__ */ new Map());
37
+ const w1 = adj.get(e.source).get(e.target) ?? 0;
38
+ adj.get(e.source).set(e.target, w1 + 1);
39
+ const w2 = adj.get(e.target).get(e.source) ?? 0;
40
+ adj.get(e.target).set(e.source, w2 + 1);
41
+ nodes.get(e.source).degree += 1;
42
+ nodes.get(e.target).degree += 1;
43
+ totalWeight += 1;
44
+ }
45
+ return { nodes, adj, totalWeight };
46
+ }
47
+ function localMovePhase(nodes, adj, totalWeight, resolution = 1) {
48
+ if (totalWeight === 0) return false;
49
+ const m2 = 2 * totalWeight;
50
+ let improved = false;
51
+ let changed = true;
52
+ let iterations = 0;
53
+ const maxIterations = 20;
54
+ const communityDegree = /* @__PURE__ */ new Map();
55
+ for (const node of nodes.values()) {
56
+ communityDegree.set(node.community, (communityDegree.get(node.community) ?? 0) + node.degree);
57
+ }
58
+ while (changed && iterations < maxIterations) {
59
+ changed = false;
60
+ iterations++;
61
+ for (const node of nodes.values()) {
62
+ const currentCommunity = node.community;
63
+ const ki = node.degree;
64
+ const neighborCommunities = /* @__PURE__ */ new Map();
65
+ const neighbors = adj.get(node.id);
66
+ if (!neighbors) continue;
67
+ for (const [neighborId, weight] of neighbors) {
68
+ const neighborNode = nodes.get(neighborId);
69
+ if (!neighborNode) continue;
70
+ const nc = neighborNode.community;
71
+ neighborCommunities.set(nc, (neighborCommunities.get(nc) ?? 0) + weight);
72
+ }
73
+ communityDegree.set(currentCommunity, (communityDegree.get(currentCommunity) ?? 0) - ki);
74
+ let bestCommunity = currentCommunity;
75
+ let bestGain = 0;
76
+ const kiIn = neighborCommunities.get(currentCommunity) ?? 0;
77
+ const sigmaCurrentWithout = communityDegree.get(currentCommunity) ?? 0;
78
+ for (const [community, edgesToCommunity] of neighborCommunities) {
79
+ if (community === currentCommunity) continue;
80
+ const sigmaCommunity = communityDegree.get(community) ?? 0;
81
+ const gain = resolution * (edgesToCommunity - kiIn) / m2 - resolution * ki * (sigmaCommunity - sigmaCurrentWithout) / (m2 * m2) * 2;
82
+ if (gain > bestGain) {
83
+ bestGain = gain;
84
+ bestCommunity = community;
85
+ }
86
+ }
87
+ if (bestCommunity !== currentCommunity) {
88
+ node.community = bestCommunity;
89
+ communityDegree.set(bestCommunity, (communityDegree.get(bestCommunity) ?? 0) + ki);
90
+ changed = true;
91
+ improved = true;
92
+ } else {
93
+ communityDegree.set(currentCommunity, (communityDegree.get(currentCommunity) ?? 0) + ki);
94
+ }
95
+ }
96
+ }
97
+ return improved;
98
+ }
99
+ function refinementPhase(nodes, adj, totalWeight, resolution = 1) {
100
+ const communityGroups = /* @__PURE__ */ new Map();
101
+ for (const node of nodes.values()) {
102
+ if (!communityGroups.has(node.community)) communityGroups.set(node.community, []);
103
+ communityGroups.get(node.community).push(node.id);
104
+ }
105
+ const m2 = 2 * totalWeight;
106
+ const refined = /* @__PURE__ */ new Map();
107
+ let nextSubId = 0;
108
+ for (const cId of communityGroups.keys()) {
109
+ if (cId >= nextSubId) nextSubId = cId + 1;
110
+ }
111
+ for (const [, members] of communityGroups) {
112
+ if (members.length === 1) {
113
+ refined.set(members[0], nextSubId++);
114
+ continue;
115
+ }
116
+ const memberSet = new Set(members);
117
+ const subCommunity = /* @__PURE__ */ new Map();
118
+ const subCommunityNodes = /* @__PURE__ */ new Map();
119
+ const subInternalEdges = /* @__PURE__ */ new Map();
120
+ const subDegree = /* @__PURE__ */ new Map();
121
+ for (const mId of members) {
122
+ const sid = nextSubId++;
123
+ subCommunity.set(mId, sid);
124
+ subCommunityNodes.set(sid, /* @__PURE__ */ new Set([mId]));
125
+ subInternalEdges.set(sid, 0);
126
+ subDegree.set(sid, nodes.get(mId).degree);
127
+ }
128
+ let mergedAny = true;
129
+ let subIterations = 0;
130
+ const maxSubIterations = 10;
131
+ while (mergedAny && subIterations < maxSubIterations) {
132
+ mergedAny = false;
133
+ subIterations++;
134
+ for (const mId of members) {
135
+ const currentSid = subCommunity.get(mId);
136
+ if (subCommunityNodes.get(currentSid).size !== 1) continue;
137
+ const ki = nodes.get(mId).degree;
138
+ const neighbors = adj.get(mId);
139
+ if (!neighbors) continue;
140
+ const edgesToSub = /* @__PURE__ */ new Map();
141
+ for (const [nId, w] of neighbors) {
142
+ if (!memberSet.has(nId)) continue;
143
+ const nSid = subCommunity.get(nId);
144
+ if (nSid === currentSid) continue;
145
+ edgesToSub.set(nSid, (edgesToSub.get(nSid) ?? 0) + w);
146
+ }
147
+ if (edgesToSub.size === 0) continue;
148
+ let bestSid = currentSid;
149
+ let bestGain = 0;
150
+ for (const [candidateSid, edgesToCandidate] of edgesToSub) {
151
+ const sigmaCandidate = subDegree.get(candidateSid) ?? 0;
152
+ const gain = resolution * edgesToCandidate / m2 - resolution * ki * sigmaCandidate / (m2 * m2) * 2;
153
+ if (gain <= bestGain) continue;
154
+ const newInternalEdges = (subInternalEdges.get(candidateSid) ?? 0) + edgesToCandidate;
155
+ const newDegreeSum = sigmaCandidate + ki;
156
+ const threshold = resolution * newDegreeSum / m2;
157
+ if (newInternalEdges < threshold) continue;
158
+ bestGain = gain;
159
+ bestSid = candidateSid;
160
+ }
161
+ if (bestSid !== currentSid) {
162
+ subCommunityNodes.get(currentSid).delete(mId);
163
+ subCommunityNodes.get(bestSid).add(mId);
164
+ subCommunity.set(mId, bestSid);
165
+ const edgesAdded = edgesToSub.get(bestSid) ?? 0;
166
+ subInternalEdges.set(bestSid, (subInternalEdges.get(bestSid) ?? 0) + edgesAdded);
167
+ subDegree.set(bestSid, (subDegree.get(bestSid) ?? 0) + ki);
168
+ mergedAny = true;
169
+ }
170
+ }
171
+ }
172
+ for (const mId of members) {
173
+ refined.set(mId, subCommunity.get(mId));
174
+ }
175
+ }
176
+ return refined;
177
+ }
178
+ function calculateModularity(nodes, adj, totalWeight) {
179
+ if (totalWeight === 0) return 0;
180
+ const m2 = 2 * totalWeight;
181
+ let q = 0;
182
+ for (const [nodeId, node] of nodes) {
183
+ const neighbors = adj.get(nodeId);
184
+ if (!neighbors) continue;
185
+ for (const [neighborId, weight] of neighbors) {
186
+ const neighborNode = nodes.get(neighborId);
187
+ if (!neighborNode) continue;
188
+ if (node.community === neighborNode.community) {
189
+ q += weight - node.degree * neighborNode.degree / m2;
190
+ }
191
+ }
192
+ }
193
+ return q / m2;
194
+ }
195
+ function detectCommunities(db, opts) {
196
+ const resolution = opts?.resolution ?? 1;
197
+ const maxCommunityPct = opts?.maxCommunityPct ?? 0.25;
198
+ const { nodes, adj, totalWeight } = buildAdjacency(db);
199
+ if (nodes.size === 0) {
200
+ return { communities: [], modularity: 0, totalNodes: 0, totalEdges: 0, algorithm: "leiden" };
201
+ }
202
+ let communityId = 0;
203
+ for (const node of nodes.values()) {
204
+ node.community = communityId++;
205
+ }
206
+ localMovePhase(nodes, adj, totalWeight, resolution);
207
+ const refinedPartition = refinementPhase(nodes, adj, totalWeight, resolution);
208
+ for (const [nodeId, refinedCommunityId] of refinedPartition) {
209
+ nodes.get(nodeId).community = refinedCommunityId;
210
+ }
211
+ const communityMembers = /* @__PURE__ */ new Map();
212
+ for (const node of nodes.values()) {
213
+ if (!communityMembers.has(node.community)) communityMembers.set(node.community, []);
214
+ communityMembers.get(node.community).push(node.id);
215
+ }
216
+ const maxSize = Math.floor(nodes.size * maxCommunityPct);
217
+ for (const [cId, members] of communityMembers) {
218
+ if (members.length > maxSize) {
219
+ const subNodes = /* @__PURE__ */ new Map();
220
+ let subCommunityId = communityId;
221
+ for (const mId of members) {
222
+ const original = nodes.get(mId);
223
+ subNodes.set(mId, { ...original, community: subCommunityId++ });
224
+ }
225
+ communityId = subCommunityId;
226
+ const subAdj = /* @__PURE__ */ new Map();
227
+ let subWeight = 0;
228
+ for (const mId of members) {
229
+ const neighbors = adj.get(mId);
230
+ if (!neighbors) continue;
231
+ for (const [nId, w] of neighbors) {
232
+ if (subNodes.has(nId)) {
233
+ if (!subAdj.has(mId)) subAdj.set(mId, /* @__PURE__ */ new Map());
234
+ subAdj.get(mId).set(nId, w);
235
+ subWeight += w;
236
+ }
237
+ }
238
+ }
239
+ localMovePhase(subNodes, subAdj, subWeight / 2, resolution * 2);
240
+ const subRefined = refinementPhase(subNodes, subAdj, subWeight / 2, resolution * 2);
241
+ for (const [mId, rId] of subRefined) {
242
+ subNodes.get(mId).community = rId;
243
+ }
244
+ for (const [mId, subNode] of subNodes) {
245
+ nodes.get(mId).community = subNode.community;
246
+ }
247
+ }
248
+ }
249
+ const rawDb = db.getRawDb();
250
+ const finalCommunities = /* @__PURE__ */ new Map();
251
+ for (const node of nodes.values()) {
252
+ if (!finalCommunities.has(node.community)) finalCommunities.set(node.community, []);
253
+ const nodeInfo = rawDb.get(
254
+ "SELECT name, kind, file_path as filePath FROM nodes WHERE id = ?",
255
+ [node.id]
256
+ );
257
+ if (nodeInfo) {
258
+ finalCommunities.get(node.community).push({
259
+ id: node.id,
260
+ name: nodeInfo.name,
261
+ kind: nodeInfo.kind,
262
+ filePath: nodeInfo.filePath
263
+ });
264
+ }
265
+ }
266
+ const interEdges = /* @__PURE__ */ new Map();
267
+ for (const [nodeId, node] of nodes) {
268
+ const neighbors = adj.get(nodeId);
269
+ if (!neighbors) continue;
270
+ for (const [neighborId] of neighbors) {
271
+ const neighborNode = nodes.get(neighborId);
272
+ if (neighborNode && neighborNode.community !== node.community) {
273
+ interEdges.set(node.community, (interEdges.get(node.community) ?? 0) + 1);
274
+ }
275
+ }
276
+ }
277
+ const communities = [];
278
+ let idx = 0;
279
+ for (const [cId, members] of finalCommunities) {
280
+ if (members.length === 0) continue;
281
+ const dirCounts = /* @__PURE__ */ new Map();
282
+ const langCounts = /* @__PURE__ */ new Map();
283
+ for (const m of members) {
284
+ const dir = m.filePath.split("/").slice(0, 2).join("/");
285
+ dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
286
+ const ext = m.filePath.split(".").pop() ?? "";
287
+ langCounts.set(ext, (langCounts.get(ext) ?? 0) + 1);
288
+ }
289
+ const dominantDirectory = [...dirCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "";
290
+ const dominantLanguage = [...langCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? "";
291
+ const label = dominantDirectory || members[0]?.name || `community-${idx}`;
292
+ communities.push({
293
+ id: idx++,
294
+ label,
295
+ memberCount: members.length,
296
+ members: members.slice(0, 30),
297
+ // Cap for output size
298
+ dominantDirectory,
299
+ dominantLanguage,
300
+ interCommunityEdges: interEdges.get(cId) ?? 0
301
+ });
302
+ }
303
+ communities.sort((a, b) => b.memberCount - a.memberCount);
304
+ const modularity = calculateModularity(nodes, adj, totalWeight);
305
+ return {
306
+ communities,
307
+ modularity,
308
+ totalNodes: nodes.size,
309
+ totalEdges: totalWeight,
310
+ algorithm: "leiden"
311
+ };
312
+ }
313
+ // Annotate the CommonJS export names for ESM import in node:
314
+ 0 && (module.exports = {
315
+ detectCommunities
316
+ });
317
+ //# sourceMappingURL=communities.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/graph/communities.ts"],
4
+ "sourcesContent": ["/**\n * Community Detection via Leiden Algorithm\n *\n * Clusters related code into communities based on edge connectivity.\n * Oversized communities (>25% of graph) are recursively split with higher resolution.\n *\n * Leiden improves on Louvain by adding a refinement phase between the local-move phase\n * and the aggregation phase. The refinement sub-partitions each community into\n * well-connected sub-communities, guaranteeing that every community in the final\n * partition is internally connected. This prevents the \"disconnected community\"\n * artefact that Louvain is known to produce.\n */\n\nimport type { GraphDatabase } from '../db/database';\n\nexport interface Community {\n id: number;\n label: string;\n memberCount: number;\n members: Array<{ id: string; name: string; kind: string; filePath: string }>;\n dominantDirectory: string;\n dominantLanguage: string;\n interCommunityEdges: number;\n}\n\nexport interface CommunityResult {\n communities: Community[];\n modularity: number;\n totalNodes: number;\n totalEdges: number;\n /** Algorithm used to detect communities. */\n algorithm: 'leiden';\n}\n\ninterface LouvainNode {\n id: string;\n community: number;\n degree: number;\n}\n\n/**\n * Build an undirected weighted adjacency from the edges table.\n * Weight = number of edges between two nodes (calls + imports + references).\n * Excludes 'contains' edges as they're structural, not semantic.\n */\nfunction buildAdjacency(db: GraphDatabase): { nodes: Map<string, LouvainNode>; adj: Map<string, Map<string, number>>; totalWeight: number } {\n const rawDb = db.getRawDb();\n\n const edges = rawDb.all(\n `SELECT source, target FROM edges WHERE kind != 'contains'`\n ) as Array<{ source: string; target: string }>;\n\n const nodes = new Map<string, LouvainNode>();\n const adj = new Map<string, Map<string, number>>();\n let totalWeight = 0;\n\n for (const e of edges) {\n // Ensure both nodes exist\n if (!nodes.has(e.source)) nodes.set(e.source, { id: e.source, community: 0, degree: 0 });\n if (!nodes.has(e.target)) nodes.set(e.target, { id: e.target, community: 0, degree: 0 });\n\n // Undirected: add weight in both directions\n if (!adj.has(e.source)) adj.set(e.source, new Map());\n if (!adj.has(e.target)) adj.set(e.target, new Map());\n\n const w1 = adj.get(e.source)!.get(e.target) ?? 0;\n adj.get(e.source)!.set(e.target, w1 + 1);\n\n const w2 = adj.get(e.target)!.get(e.source) ?? 0;\n adj.get(e.target)!.set(e.source, w2 + 1);\n\n nodes.get(e.source)!.degree += 1;\n nodes.get(e.target)!.degree += 1;\n totalWeight += 1;\n }\n\n return { nodes, adj, totalWeight };\n}\n\n/**\n * Leiden/Louvain Phase 1 \u2014 local moving.\n *\n * For each node, try moving it to the neighbouring community that yields the\n * largest positive modularity gain. Repeats until no improvement is found or\n * `maxIterations` is reached.\n */\nfunction localMovePhase(\n nodes: Map<string, LouvainNode>,\n adj: Map<string, Map<string, number>>,\n totalWeight: number,\n resolution: number = 1.0,\n): boolean {\n if (totalWeight === 0) return false;\n\n const m2 = 2 * totalWeight;\n let improved = false;\n let changed = true;\n let iterations = 0;\n const maxIterations = 20;\n\n // Community totals: sum of degrees of nodes in each community\n const communityDegree = new Map<number, number>();\n for (const node of nodes.values()) {\n communityDegree.set(node.community, (communityDegree.get(node.community) ?? 0) + node.degree);\n }\n\n while (changed && iterations < maxIterations) {\n changed = false;\n iterations++;\n\n for (const node of nodes.values()) {\n const currentCommunity = node.community;\n const ki = node.degree;\n\n // Calculate edges to each neighbouring community\n const neighborCommunities = new Map<number, number>();\n const neighbors = adj.get(node.id);\n if (!neighbors) continue;\n\n for (const [neighborId, weight] of neighbors) {\n const neighborNode = nodes.get(neighborId);\n if (!neighborNode) continue;\n const nc = neighborNode.community;\n neighborCommunities.set(nc, (neighborCommunities.get(nc) ?? 0) + weight);\n }\n\n // Remove node from its current community\n communityDegree.set(currentCommunity, (communityDegree.get(currentCommunity) ?? 0) - ki);\n\n // Find best community\n let bestCommunity = currentCommunity;\n let bestGain = 0;\n\n const kiIn = neighborCommunities.get(currentCommunity) ?? 0;\n const sigmaCurrentWithout = communityDegree.get(currentCommunity) ?? 0;\n\n for (const [community, edgesToCommunity] of neighborCommunities) {\n if (community === currentCommunity) continue;\n\n const sigmaCommunity = communityDegree.get(community) ?? 0;\n\n // Modularity gain formula\n const gain = resolution * (edgesToCommunity - kiIn) / m2\n - resolution * ki * (sigmaCommunity - sigmaCurrentWithout) / (m2 * m2) * 2;\n\n if (gain > bestGain) {\n bestGain = gain;\n bestCommunity = community;\n }\n }\n\n // Move node to best community\n if (bestCommunity !== currentCommunity) {\n node.community = bestCommunity;\n communityDegree.set(bestCommunity, (communityDegree.get(bestCommunity) ?? 0) + ki);\n changed = true;\n improved = true;\n } else {\n communityDegree.set(currentCommunity, (communityDegree.get(currentCommunity) ?? 0) + ki);\n }\n }\n }\n\n return improved;\n}\n\n/**\n * Leiden Phase 2 \u2014 refinement.\n *\n * For each community produced by the local-move phase, attempt to split it into\n * smaller, well-connected sub-communities. This prevents the disconnected-community\n * artefact that plain Louvain can produce.\n *\n * The procedure:\n * 1. Collect the nodes that belong to community C.\n * 2. Start with every node in its own singleton sub-community.\n * 3. For each node, consider merging its singleton into an adjacent\n * sub-community (within C) if the merge yields a positive modularity gain\n * AND the resulting sub-community remains well-connected (internal edges \u2265\n * a connectivity threshold derived from the sub-community's total degree).\n * 4. Write the refined sub-community ids back into a new partition map.\n *\n * Returns a map from original node id \u2192 refined community id.\n */\nfunction refinementPhase(\n nodes: Map<string, LouvainNode>,\n adj: Map<string, Map<string, number>>,\n totalWeight: number,\n resolution: number = 1.0,\n): Map<string, number> {\n // Group nodes by their current (post-local-move) community\n const communityGroups = new Map<number, string[]>();\n for (const node of nodes.values()) {\n if (!communityGroups.has(node.community)) communityGroups.set(node.community, []);\n communityGroups.get(node.community)!.push(node.id);\n }\n\n const m2 = 2 * totalWeight;\n // Output: node id \u2192 refined community id\n const refined = new Map<string, number>();\n\n // Use a globally incrementing id so refined sub-communities never collide\n let nextSubId = 0;\n // Initialise: reserve unique ids based on current community ids to avoid\n // collisions even before we start assigning new ones\n for (const cId of communityGroups.keys()) {\n if (cId >= nextSubId) nextSubId = cId + 1;\n }\n\n for (const [, members] of communityGroups) {\n if (members.length === 1) {\n // Singleton community \u2014 nothing to refine\n refined.set(members[0], nextSubId++);\n continue;\n }\n\n const memberSet = new Set(members);\n\n // Phase 2a: start with each node in its own singleton sub-community\n const subCommunity = new Map<string, number>(); // node id \u2192 sub-community id\n const subCommunityNodes = new Map<number, Set<string>>(); // sub-community id \u2192 node ids\n // Internal edge weight for each sub-community\n const subInternalEdges = new Map<number, number>();\n // Total degree for each sub-community (within the full graph, not just sub-graph)\n const subDegree = new Map<number, number>();\n\n for (const mId of members) {\n const sid = nextSubId++;\n subCommunity.set(mId, sid);\n subCommunityNodes.set(sid, new Set([mId]));\n subInternalEdges.set(sid, 0);\n subDegree.set(sid, nodes.get(mId)!.degree);\n }\n\n // Phase 2b: iteratively merge singletons into well-connected sub-communities\n // We only allow merging a node if it is currently a singleton (size 1)\n // \u2014 this keeps the procedure efficient and follows the Leiden paper's spirit.\n let mergedAny = true;\n let subIterations = 0;\n const maxSubIterations = 10;\n\n while (mergedAny && subIterations < maxSubIterations) {\n mergedAny = false;\n subIterations++;\n\n for (const mId of members) {\n const currentSid = subCommunity.get(mId)!;\n // Only try to move nodes that are still singletons\n if (subCommunityNodes.get(currentSid)!.size !== 1) continue;\n\n const ki = nodes.get(mId)!.degree;\n const neighbors = adj.get(mId);\n if (!neighbors) continue;\n\n // Count edges from this node to each sub-community (within the same community C)\n const edgesToSub = new Map<number, number>();\n for (const [nId, w] of neighbors) {\n if (!memberSet.has(nId)) continue;\n const nSid = subCommunity.get(nId)!;\n if (nSid === currentSid) continue;\n edgesToSub.set(nSid, (edgesToSub.get(nSid) ?? 0) + w);\n }\n\n if (edgesToSub.size === 0) continue;\n\n let bestSid = currentSid;\n let bestGain = 0;\n\n for (const [candidateSid, edgesToCandidate] of edgesToSub) {\n const sigmaCandidate = subDegree.get(candidateSid) ?? 0;\n\n // Modularity gain of merging this singleton into candidateSid\n const gain = resolution * edgesToCandidate / m2\n - resolution * ki * sigmaCandidate / (m2 * m2) * 2;\n\n if (gain <= bestGain) continue;\n\n // Well-connectedness check:\n // After the merge the sub-community's internal edges would be\n // (current internal edges of candidate) + (edges from mId to candidate).\n // The threshold is: internalEdges >= \u03B3 * (degree_sum * (degree_sum - ki)) / (2m)\n // We use a relaxed form: internal edges must be positive (at least one edge\n // into the sub-community), which is already guaranteed by edgesToCandidate > 0.\n // Additionally enforce that the density ratio doesn't drop below a floor.\n const newInternalEdges = (subInternalEdges.get(candidateSid) ?? 0) + edgesToCandidate;\n const newDegreeSum = sigmaCandidate + ki;\n // Connectivity threshold: internal edge weight >= resolution * newDegreeSum / (2m)\n const threshold = resolution * newDegreeSum / m2;\n if (newInternalEdges < threshold) continue;\n\n bestGain = gain;\n bestSid = candidateSid;\n }\n\n if (bestSid !== currentSid) {\n // Perform the merge\n subCommunityNodes.get(currentSid)!.delete(mId);\n subCommunityNodes.get(bestSid)!.add(mId);\n subCommunity.set(mId, bestSid);\n\n const edgesAdded = edgesToSub.get(bestSid) ?? 0;\n subInternalEdges.set(bestSid, (subInternalEdges.get(bestSid) ?? 0) + edgesAdded);\n subDegree.set(bestSid, (subDegree.get(bestSid) ?? 0) + ki);\n\n mergedAny = true;\n }\n }\n }\n\n // Write refined assignments into the output map\n for (const mId of members) {\n refined.set(mId, subCommunity.get(mId)!);\n }\n }\n\n return refined;\n}\n\n/**\n * Calculate modularity of the current partition.\n */\nfunction calculateModularity(\n nodes: Map<string, LouvainNode>,\n adj: Map<string, Map<string, number>>,\n totalWeight: number,\n): number {\n if (totalWeight === 0) return 0;\n\n const m2 = 2 * totalWeight;\n let q = 0;\n\n for (const [nodeId, node] of nodes) {\n const neighbors = adj.get(nodeId);\n if (!neighbors) continue;\n\n for (const [neighborId, weight] of neighbors) {\n const neighborNode = nodes.get(neighborId);\n if (!neighborNode) continue;\n\n if (node.community === neighborNode.community) {\n q += weight - (node.degree * neighborNode.degree) / m2;\n }\n }\n }\n\n return q / m2;\n}\n\n/**\n * Run community detection on the graph using the Leiden algorithm.\n */\nexport function detectCommunities(db: GraphDatabase, opts?: { resolution?: number; maxCommunityPct?: number }): CommunityResult {\n const resolution = opts?.resolution ?? 1.0;\n const maxCommunityPct = opts?.maxCommunityPct ?? 0.25;\n\n const { nodes, adj, totalWeight } = buildAdjacency(db);\n\n if (nodes.size === 0) {\n return { communities: [], modularity: 0, totalNodes: 0, totalEdges: 0, algorithm: 'leiden' };\n }\n\n // Initialize: each node in its own community\n let communityId = 0;\n for (const node of nodes.values()) {\n node.community = communityId++;\n }\n\n // --- Leiden: local-move phase ---\n localMovePhase(nodes, adj, totalWeight, resolution);\n\n // --- Leiden: refinement phase ---\n // Sub-partition each community into well-connected sub-communities, then apply\n // the refined assignments back to the nodes map before aggregation.\n const refinedPartition = refinementPhase(nodes, adj, totalWeight, resolution);\n for (const [nodeId, refinedCommunityId] of refinedPartition) {\n nodes.get(nodeId)!.community = refinedCommunityId;\n }\n\n // Auto-split oversized communities\n const communityMembers = new Map<number, string[]>();\n for (const node of nodes.values()) {\n if (!communityMembers.has(node.community)) communityMembers.set(node.community, []);\n communityMembers.get(node.community)!.push(node.id);\n }\n\n const maxSize = Math.floor(nodes.size * maxCommunityPct);\n for (const [cId, members] of communityMembers) {\n if (members.length > maxSize) {\n // Re-run with higher resolution on this subgraph\n const subNodes = new Map<string, LouvainNode>();\n let subCommunityId = communityId;\n for (const mId of members) {\n const original = nodes.get(mId)!;\n subNodes.set(mId, { ...original, community: subCommunityId++ });\n }\n communityId = subCommunityId;\n\n // Build sub-adjacency\n const subAdj = new Map<string, Map<string, number>>();\n let subWeight = 0;\n for (const mId of members) {\n const neighbors = adj.get(mId);\n if (!neighbors) continue;\n for (const [nId, w] of neighbors) {\n if (subNodes.has(nId)) {\n if (!subAdj.has(mId)) subAdj.set(mId, new Map());\n subAdj.get(mId)!.set(nId, w);\n subWeight += w;\n }\n }\n }\n\n // Leiden on the sub-graph: local move + refinement\n localMovePhase(subNodes, subAdj, subWeight / 2, resolution * 2);\n const subRefined = refinementPhase(subNodes, subAdj, subWeight / 2, resolution * 2);\n for (const [mId, rId] of subRefined) {\n subNodes.get(mId)!.community = rId;\n }\n\n // Apply sub-community assignments back\n for (const [mId, subNode] of subNodes) {\n nodes.get(mId)!.community = subNode.community;\n }\n }\n }\n\n // Build result\n const rawDb = db.getRawDb();\n const finalCommunities = new Map<number, Array<{ id: string; name: string; kind: string; filePath: string }>>();\n\n for (const node of nodes.values()) {\n if (!finalCommunities.has(node.community)) finalCommunities.set(node.community, []);\n const nodeInfo = rawDb.get(\n 'SELECT name, kind, file_path as filePath FROM nodes WHERE id = ?',\n [node.id]\n ) as any;\n if (nodeInfo) {\n finalCommunities.get(node.community)!.push({\n id: node.id,\n name: nodeInfo.name,\n kind: nodeInfo.kind,\n filePath: nodeInfo.filePath,\n });\n }\n }\n\n // Calculate inter-community edges\n const interEdges = new Map<number, number>();\n for (const [nodeId, node] of nodes) {\n const neighbors = adj.get(nodeId);\n if (!neighbors) continue;\n for (const [neighborId] of neighbors) {\n const neighborNode = nodes.get(neighborId);\n if (neighborNode && neighborNode.community !== node.community) {\n interEdges.set(node.community, (interEdges.get(node.community) ?? 0) + 1);\n }\n }\n }\n\n // Build community objects\n const communities: Community[] = [];\n let idx = 0;\n for (const [cId, members] of finalCommunities) {\n if (members.length === 0) continue;\n\n // Dominant directory\n const dirCounts = new Map<string, number>();\n const langCounts = new Map<string, number>();\n for (const m of members) {\n const dir = m.filePath.split('/').slice(0, 2).join('/');\n dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);\n const ext = m.filePath.split('.').pop() ?? '';\n langCounts.set(ext, (langCounts.get(ext) ?? 0) + 1);\n }\n\n const dominantDirectory = [...dirCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';\n const dominantLanguage = [...langCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ?? '';\n\n // Generate label from dominant directory or top symbol\n const label = dominantDirectory || members[0]?.name || `community-${idx}`;\n\n communities.push({\n id: idx++,\n label,\n memberCount: members.length,\n members: members.slice(0, 30), // Cap for output size\n dominantDirectory,\n dominantLanguage,\n interCommunityEdges: interEdges.get(cId) ?? 0,\n });\n }\n\n // Sort by size descending\n communities.sort((a, b) => b.memberCount - a.memberCount);\n\n const modularity = calculateModularity(nodes, adj, totalWeight);\n\n return {\n communities,\n modularity,\n totalNodes: nodes.size,\n totalEdges: totalWeight,\n algorithm: 'leiden',\n };\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA6CA,SAAS,eAAe,IAAoH;AAC1I,QAAM,QAAQ,GAAG,SAAS;AAE1B,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,QAAQ,oBAAI,IAAyB;AAC3C,QAAM,MAAM,oBAAI,IAAiC;AACjD,MAAI,cAAc;AAElB,aAAW,KAAK,OAAO;AAErB,QAAI,CAAC,MAAM,IAAI,EAAE,MAAM,EAAG,OAAM,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,WAAW,GAAG,QAAQ,EAAE,CAAC;AACvF,QAAI,CAAC,MAAM,IAAI,EAAE,MAAM,EAAG,OAAM,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,WAAW,GAAG,QAAQ,EAAE,CAAC;AAGvF,QAAI,CAAC,IAAI,IAAI,EAAE,MAAM,EAAG,KAAI,IAAI,EAAE,QAAQ,oBAAI,IAAI,CAAC;AACnD,QAAI,CAAC,IAAI,IAAI,EAAE,MAAM,EAAG,KAAI,IAAI,EAAE,QAAQ,oBAAI,IAAI,CAAC;AAEnD,UAAM,KAAK,IAAI,IAAI,EAAE,MAAM,EAAG,IAAI,EAAE,MAAM,KAAK;AAC/C,QAAI,IAAI,EAAE,MAAM,EAAG,IAAI,EAAE,QAAQ,KAAK,CAAC;AAEvC,UAAM,KAAK,IAAI,IAAI,EAAE,MAAM,EAAG,IAAI,EAAE,MAAM,KAAK;AAC/C,QAAI,IAAI,EAAE,MAAM,EAAG,IAAI,EAAE,QAAQ,KAAK,CAAC;AAEvC,UAAM,IAAI,EAAE,MAAM,EAAG,UAAU;AAC/B,UAAM,IAAI,EAAE,MAAM,EAAG,UAAU;AAC/B,mBAAe;AAAA,EACjB;AAEA,SAAO,EAAE,OAAO,KAAK,YAAY;AACnC;AASA,SAAS,eACP,OACA,KACA,aACA,aAAqB,GACZ;AACT,MAAI,gBAAgB,EAAG,QAAO;AAE9B,QAAM,KAAK,IAAI;AACf,MAAI,WAAW;AACf,MAAI,UAAU;AACd,MAAI,aAAa;AACjB,QAAM,gBAAgB;AAGtB,QAAM,kBAAkB,oBAAI,IAAoB;AAChD,aAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,oBAAgB,IAAI,KAAK,YAAY,gBAAgB,IAAI,KAAK,SAAS,KAAK,KAAK,KAAK,MAAM;AAAA,EAC9F;AAEA,SAAO,WAAW,aAAa,eAAe;AAC5C,cAAU;AACV;AAEA,eAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,YAAM,mBAAmB,KAAK;AAC9B,YAAM,KAAK,KAAK;AAGhB,YAAM,sBAAsB,oBAAI,IAAoB;AACpD,YAAM,YAAY,IAAI,IAAI,KAAK,EAAE;AACjC,UAAI,CAAC,UAAW;AAEhB,iBAAW,CAAC,YAAY,MAAM,KAAK,WAAW;AAC5C,cAAM,eAAe,MAAM,IAAI,UAAU;AACzC,YAAI,CAAC,aAAc;AACnB,cAAM,KAAK,aAAa;AACxB,4BAAoB,IAAI,KAAK,oBAAoB,IAAI,EAAE,KAAK,KAAK,MAAM;AAAA,MACzE;AAGA,sBAAgB,IAAI,mBAAmB,gBAAgB,IAAI,gBAAgB,KAAK,KAAK,EAAE;AAGvF,UAAI,gBAAgB;AACpB,UAAI,WAAW;AAEf,YAAM,OAAO,oBAAoB,IAAI,gBAAgB,KAAK;AAC1D,YAAM,sBAAsB,gBAAgB,IAAI,gBAAgB,KAAK;AAErE,iBAAW,CAAC,WAAW,gBAAgB,KAAK,qBAAqB;AAC/D,YAAI,cAAc,iBAAkB;AAEpC,cAAM,iBAAiB,gBAAgB,IAAI,SAAS,KAAK;AAGzD,cAAM,OAAO,cAAc,mBAAmB,QAAQ,KAClD,aAAa,MAAM,iBAAiB,wBAAwB,KAAK,MAAM;AAE3E,YAAI,OAAO,UAAU;AACnB,qBAAW;AACX,0BAAgB;AAAA,QAClB;AAAA,MACF;AAGA,UAAI,kBAAkB,kBAAkB;AACtC,aAAK,YAAY;AACjB,wBAAgB,IAAI,gBAAgB,gBAAgB,IAAI,aAAa,KAAK,KAAK,EAAE;AACjF,kBAAU;AACV,mBAAW;AAAA,MACb,OAAO;AACL,wBAAgB,IAAI,mBAAmB,gBAAgB,IAAI,gBAAgB,KAAK,KAAK,EAAE;AAAA,MACzF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAoBA,SAAS,gBACP,OACA,KACA,aACA,aAAqB,GACA;AAErB,QAAM,kBAAkB,oBAAI,IAAsB;AAClD,aAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,QAAI,CAAC,gBAAgB,IAAI,KAAK,SAAS,EAAG,iBAAgB,IAAI,KAAK,WAAW,CAAC,CAAC;AAChF,oBAAgB,IAAI,KAAK,SAAS,EAAG,KAAK,KAAK,EAAE;AAAA,EACnD;AAEA,QAAM,KAAK,IAAI;AAEf,QAAM,UAAU,oBAAI,IAAoB;AAGxC,MAAI,YAAY;AAGhB,aAAW,OAAO,gBAAgB,KAAK,GAAG;AACxC,QAAI,OAAO,UAAW,aAAY,MAAM;AAAA,EAC1C;AAEA,aAAW,CAAC,EAAE,OAAO,KAAK,iBAAiB;AACzC,QAAI,QAAQ,WAAW,GAAG;AAExB,cAAQ,IAAI,QAAQ,CAAC,GAAG,WAAW;AACnC;AAAA,IACF;AAEA,UAAM,YAAY,IAAI,IAAI,OAAO;AAGjC,UAAM,eAAe,oBAAI,IAAoB;AAC7C,UAAM,oBAAoB,oBAAI,IAAyB;AAEvD,UAAM,mBAAmB,oBAAI,IAAoB;AAEjD,UAAM,YAAY,oBAAI,IAAoB;AAE1C,eAAW,OAAO,SAAS;AACzB,YAAM,MAAM;AACZ,mBAAa,IAAI,KAAK,GAAG;AACzB,wBAAkB,IAAI,KAAK,oBAAI,IAAI,CAAC,GAAG,CAAC,CAAC;AACzC,uBAAiB,IAAI,KAAK,CAAC;AAC3B,gBAAU,IAAI,KAAK,MAAM,IAAI,GAAG,EAAG,MAAM;AAAA,IAC3C;AAKA,QAAI,YAAY;AAChB,QAAI,gBAAgB;AACpB,UAAM,mBAAmB;AAEzB,WAAO,aAAa,gBAAgB,kBAAkB;AACpD,kBAAY;AACZ;AAEA,iBAAW,OAAO,SAAS;AACzB,cAAM,aAAa,aAAa,IAAI,GAAG;AAEvC,YAAI,kBAAkB,IAAI,UAAU,EAAG,SAAS,EAAG;AAEnD,cAAM,KAAK,MAAM,IAAI,GAAG,EAAG;AAC3B,cAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,YAAI,CAAC,UAAW;AAGhB,cAAM,aAAa,oBAAI,IAAoB;AAC3C,mBAAW,CAAC,KAAK,CAAC,KAAK,WAAW;AAChC,cAAI,CAAC,UAAU,IAAI,GAAG,EAAG;AACzB,gBAAM,OAAO,aAAa,IAAI,GAAG;AACjC,cAAI,SAAS,WAAY;AACzB,qBAAW,IAAI,OAAO,WAAW,IAAI,IAAI,KAAK,KAAK,CAAC;AAAA,QACtD;AAEA,YAAI,WAAW,SAAS,EAAG;AAE3B,YAAI,UAAU;AACd,YAAI,WAAW;AAEf,mBAAW,CAAC,cAAc,gBAAgB,KAAK,YAAY;AACzD,gBAAM,iBAAiB,UAAU,IAAI,YAAY,KAAK;AAGtD,gBAAM,OAAO,aAAa,mBAAmB,KACzC,aAAa,KAAK,kBAAkB,KAAK,MAAM;AAEnD,cAAI,QAAQ,SAAU;AAStB,gBAAM,oBAAoB,iBAAiB,IAAI,YAAY,KAAK,KAAK;AACrE,gBAAM,eAAe,iBAAiB;AAEtC,gBAAM,YAAY,aAAa,eAAe;AAC9C,cAAI,mBAAmB,UAAW;AAElC,qBAAW;AACX,oBAAU;AAAA,QACZ;AAEA,YAAI,YAAY,YAAY;AAE1B,4BAAkB,IAAI,UAAU,EAAG,OAAO,GAAG;AAC7C,4BAAkB,IAAI,OAAO,EAAG,IAAI,GAAG;AACvC,uBAAa,IAAI,KAAK,OAAO;AAE7B,gBAAM,aAAa,WAAW,IAAI,OAAO,KAAK;AAC9C,2BAAiB,IAAI,UAAU,iBAAiB,IAAI,OAAO,KAAK,KAAK,UAAU;AAC/E,oBAAU,IAAI,UAAU,UAAU,IAAI,OAAO,KAAK,KAAK,EAAE;AAEzD,sBAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AAGA,eAAW,OAAO,SAAS;AACzB,cAAQ,IAAI,KAAK,aAAa,IAAI,GAAG,CAAE;AAAA,IACzC;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,oBACP,OACA,KACA,aACQ;AACR,MAAI,gBAAgB,EAAG,QAAO;AAE9B,QAAM,KAAK,IAAI;AACf,MAAI,IAAI;AAER,aAAW,CAAC,QAAQ,IAAI,KAAK,OAAO;AAClC,UAAM,YAAY,IAAI,IAAI,MAAM;AAChC,QAAI,CAAC,UAAW;AAEhB,eAAW,CAAC,YAAY,MAAM,KAAK,WAAW;AAC5C,YAAM,eAAe,MAAM,IAAI,UAAU;AACzC,UAAI,CAAC,aAAc;AAEnB,UAAI,KAAK,cAAc,aAAa,WAAW;AAC7C,aAAK,SAAU,KAAK,SAAS,aAAa,SAAU;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAEA,SAAO,IAAI;AACb;AAKO,SAAS,kBAAkB,IAAmB,MAA2E;AAC9H,QAAM,aAAa,MAAM,cAAc;AACvC,QAAM,kBAAkB,MAAM,mBAAmB;AAEjD,QAAM,EAAE,OAAO,KAAK,YAAY,IAAI,eAAe,EAAE;AAErD,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO,EAAE,aAAa,CAAC,GAAG,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,WAAW,SAAS;AAAA,EAC7F;AAGA,MAAI,cAAc;AAClB,aAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,SAAK,YAAY;AAAA,EACnB;AAGA,iBAAe,OAAO,KAAK,aAAa,UAAU;AAKlD,QAAM,mBAAmB,gBAAgB,OAAO,KAAK,aAAa,UAAU;AAC5E,aAAW,CAAC,QAAQ,kBAAkB,KAAK,kBAAkB;AAC3D,UAAM,IAAI,MAAM,EAAG,YAAY;AAAA,EACjC;AAGA,QAAM,mBAAmB,oBAAI,IAAsB;AACnD,aAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,QAAI,CAAC,iBAAiB,IAAI,KAAK,SAAS,EAAG,kBAAiB,IAAI,KAAK,WAAW,CAAC,CAAC;AAClF,qBAAiB,IAAI,KAAK,SAAS,EAAG,KAAK,KAAK,EAAE;AAAA,EACpD;AAEA,QAAM,UAAU,KAAK,MAAM,MAAM,OAAO,eAAe;AACvD,aAAW,CAAC,KAAK,OAAO,KAAK,kBAAkB;AAC7C,QAAI,QAAQ,SAAS,SAAS;AAE5B,YAAM,WAAW,oBAAI,IAAyB;AAC9C,UAAI,iBAAiB;AACrB,iBAAW,OAAO,SAAS;AACzB,cAAM,WAAW,MAAM,IAAI,GAAG;AAC9B,iBAAS,IAAI,KAAK,EAAE,GAAG,UAAU,WAAW,iBAAiB,CAAC;AAAA,MAChE;AACA,oBAAc;AAGd,YAAM,SAAS,oBAAI,IAAiC;AACpD,UAAI,YAAY;AAChB,iBAAW,OAAO,SAAS;AACzB,cAAM,YAAY,IAAI,IAAI,GAAG;AAC7B,YAAI,CAAC,UAAW;AAChB,mBAAW,CAAC,KAAK,CAAC,KAAK,WAAW;AAChC,cAAI,SAAS,IAAI,GAAG,GAAG;AACrB,gBAAI,CAAC,OAAO,IAAI,GAAG,EAAG,QAAO,IAAI,KAAK,oBAAI,IAAI,CAAC;AAC/C,mBAAO,IAAI,GAAG,EAAG,IAAI,KAAK,CAAC;AAC3B,yBAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAGA,qBAAe,UAAU,QAAQ,YAAY,GAAG,aAAa,CAAC;AAC9D,YAAM,aAAa,gBAAgB,UAAU,QAAQ,YAAY,GAAG,aAAa,CAAC;AAClF,iBAAW,CAAC,KAAK,GAAG,KAAK,YAAY;AACnC,iBAAS,IAAI,GAAG,EAAG,YAAY;AAAA,MACjC;AAGA,iBAAW,CAAC,KAAK,OAAO,KAAK,UAAU;AACrC,cAAM,IAAI,GAAG,EAAG,YAAY,QAAQ;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAGA,QAAM,QAAQ,GAAG,SAAS;AAC1B,QAAM,mBAAmB,oBAAI,IAAiF;AAE9G,aAAW,QAAQ,MAAM,OAAO,GAAG;AACjC,QAAI,CAAC,iBAAiB,IAAI,KAAK,SAAS,EAAG,kBAAiB,IAAI,KAAK,WAAW,CAAC,CAAC;AAClF,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,CAAC,KAAK,EAAE;AAAA,IACV;AACA,QAAI,UAAU;AACZ,uBAAiB,IAAI,KAAK,SAAS,EAAG,KAAK;AAAA,QACzC,IAAI,KAAK;AAAA,QACT,MAAM,SAAS;AAAA,QACf,MAAM,SAAS;AAAA,QACf,UAAU,SAAS;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,aAAa,oBAAI,IAAoB;AAC3C,aAAW,CAAC,QAAQ,IAAI,KAAK,OAAO;AAClC,UAAM,YAAY,IAAI,IAAI,MAAM;AAChC,QAAI,CAAC,UAAW;AAChB,eAAW,CAAC,UAAU,KAAK,WAAW;AACpC,YAAM,eAAe,MAAM,IAAI,UAAU;AACzC,UAAI,gBAAgB,aAAa,cAAc,KAAK,WAAW;AAC7D,mBAAW,IAAI,KAAK,YAAY,WAAW,IAAI,KAAK,SAAS,KAAK,KAAK,CAAC;AAAA,MAC1E;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAA2B,CAAC;AAClC,MAAI,MAAM;AACV,aAAW,CAAC,KAAK,OAAO,KAAK,kBAAkB;AAC7C,QAAI,QAAQ,WAAW,EAAG;AAG1B,UAAM,YAAY,oBAAI,IAAoB;AAC1C,UAAM,aAAa,oBAAI,IAAoB;AAC3C,eAAW,KAAK,SAAS;AACvB,YAAM,MAAM,EAAE,SAAS,MAAM,GAAG,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,GAAG;AACtD,gBAAU,IAAI,MAAM,UAAU,IAAI,GAAG,KAAK,KAAK,CAAC;AAChD,YAAM,MAAM,EAAE,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC3C,iBAAW,IAAI,MAAM,WAAW,IAAI,GAAG,KAAK,KAAK,CAAC;AAAA,IACpD;AAEA,UAAM,oBAAoB,CAAC,GAAG,UAAU,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAC1F,UAAM,mBAAmB,CAAC,GAAG,WAAW,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK;AAG1F,UAAM,QAAQ,qBAAqB,QAAQ,CAAC,GAAG,QAAQ,aAAa,GAAG;AAEvE,gBAAY,KAAK;AAAA,MACf,IAAI;AAAA,MACJ;AAAA,MACA,aAAa,QAAQ;AAAA,MACrB,SAAS,QAAQ,MAAM,GAAG,EAAE;AAAA;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,qBAAqB,WAAW,IAAI,GAAG,KAAK;AAAA,IAC9C,CAAC;AAAA,EACH;AAGA,cAAY,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,EAAE,WAAW;AAExD,QAAM,aAAa,oBAAoB,OAAO,KAAK,WAAW;AAE9D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,MAAM;AAAA,IAClB,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,138 @@
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 flows_exports = {};
20
+ __export(flows_exports, {
21
+ detectEntryPoints: () => detectEntryPoints,
22
+ getExecutionFlows: () => getExecutionFlows,
23
+ scoreCriticality: () => scoreCriticality,
24
+ traceFlow: () => traceFlow
25
+ });
26
+ module.exports = __toCommonJS(flows_exports);
27
+ function detectEntryPoints(db, limit = 20) {
28
+ const rawDb = db.getRawDb();
29
+ const routes = rawDb.all(
30
+ `SELECT id, name, kind, file_path as filePath, start_line as line FROM nodes WHERE kind = 'route' LIMIT ?`,
31
+ [limit]
32
+ );
33
+ const roots = rawDb.all(
34
+ `SELECT n.id, n.name, n.kind, n.file_path as filePath, n.start_line as line
35
+ FROM nodes n
36
+ WHERE n.kind IN ('function', 'method')
37
+ AND n.is_exported = 1
38
+ AND NOT EXISTS (
39
+ SELECT 1 FROM edges e WHERE e.target = n.id AND e.kind = 'calls'
40
+ )
41
+ ORDER BY (SELECT COUNT(*) FROM edges e2 WHERE e2.source = n.id) DESC
42
+ LIMIT ?`,
43
+ [limit]
44
+ );
45
+ const patterns = rawDb.all(
46
+ `SELECT id, name, kind, file_path as filePath, start_line as line FROM nodes
47
+ WHERE (lower(name) LIKE '%handler%' OR lower(name) LIKE '%controller%'
48
+ OR lower(name) = 'main' OR lower(name) LIKE '%middleware%'
49
+ OR lower(name) LIKE '%endpoint%')
50
+ AND kind IN ('function', 'method', 'class')
51
+ LIMIT ?`,
52
+ [limit]
53
+ );
54
+ const seen = /* @__PURE__ */ new Set();
55
+ const results = [];
56
+ for (const entry of [...routes, ...roots, ...patterns]) {
57
+ if (!seen.has(entry.id)) {
58
+ seen.add(entry.id);
59
+ results.push(entry);
60
+ }
61
+ }
62
+ return results.slice(0, limit);
63
+ }
64
+ function traceFlow(db, entryPointId, maxDepth = 10) {
65
+ const rawDb = db.getRawDb();
66
+ const hops = [];
67
+ const visited = /* @__PURE__ */ new Set();
68
+ function walk(nodeId, depth) {
69
+ if (depth >= maxDepth || visited.has(nodeId)) return;
70
+ visited.add(nodeId);
71
+ const node = rawDb.get(
72
+ "SELECT name, kind, file_path as filePath, start_line as line FROM nodes WHERE id = ?",
73
+ [nodeId]
74
+ );
75
+ if (!node) return;
76
+ const edgeInfo = depth === 0 ? void 0 : rawDb.get(
77
+ `SELECT kind, confidence FROM edges WHERE target = ? AND source IN (${[...visited].map(() => "?").join(",")}) LIMIT 1`,
78
+ [nodeId, ...[...visited]]
79
+ );
80
+ hops.push({
81
+ symbol: node.name,
82
+ kind: node.kind,
83
+ filePath: node.filePath,
84
+ line: node.line,
85
+ edgeKind: edgeInfo?.kind,
86
+ confidence: edgeInfo?.confidence
87
+ });
88
+ const callees = rawDb.all(
89
+ `SELECT e.target, e.kind as edgeKind, e.confidence
90
+ FROM edges e
91
+ WHERE e.source = ? AND e.kind = 'calls'
92
+ ORDER BY (SELECT COUNT(*) FROM edges e2 WHERE e2.source = e.target) DESC
93
+ LIMIT 5`,
94
+ [nodeId]
95
+ );
96
+ for (const callee of callees) {
97
+ walk(callee.target, depth + 1);
98
+ }
99
+ }
100
+ walk(entryPointId, 0);
101
+ return hops;
102
+ }
103
+ function scoreCriticality(hops) {
104
+ if (hops.length === 0) return 0;
105
+ const lengthScore = Math.min(hops.length / 10, 1);
106
+ const ioPatterns = /db|database|query|http|fetch|request|file|write|read|socket|stream/i;
107
+ const touchesIO = hops.some((h) => ioPatterns.test(h.symbol));
108
+ const ioScore = touchesIO ? 0.3 : 0;
109
+ return Math.min(lengthScore * 0.7 + ioScore, 1);
110
+ }
111
+ function getExecutionFlows(db, opts) {
112
+ const maxFlows = opts?.maxFlows ?? 15;
113
+ const maxDepth = opts?.maxDepth ?? 10;
114
+ const entryPoints = detectEntryPoints(db, maxFlows * 2);
115
+ const flows = [];
116
+ for (const ep of entryPoints) {
117
+ const hops = traceFlow(db, ep.id, maxDepth);
118
+ if (hops.length < 2) continue;
119
+ const criticality = scoreCriticality(hops);
120
+ flows.push({
121
+ entryPoint: ep.name,
122
+ entryPointKind: ep.kind,
123
+ entryPointFile: ep.filePath,
124
+ criticality,
125
+ hops
126
+ });
127
+ }
128
+ flows.sort((a, b) => b.criticality - a.criticality);
129
+ return flows.slice(0, maxFlows);
130
+ }
131
+ // Annotate the CommonJS export names for ESM import in node:
132
+ 0 && (module.exports = {
133
+ detectEntryPoints,
134
+ getExecutionFlows,
135
+ scoreCriticality,
136
+ traceFlow
137
+ });
138
+ //# sourceMappingURL=flows.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/graph/flows.ts"],
4
+ "sourcesContent": ["/**\n * Execution Flow Tracing\n *\n * Traces call chains from entry points (functions with no incoming call edges,\n * route handlers, main functions) through the graph, sorted by criticality.\n */\n\nimport type { GraphDatabase } from '../db/database';\n\nexport interface FlowHop {\n symbol: string;\n kind: string;\n filePath: string;\n line: number;\n edgeKind?: string;\n confidence?: string;\n}\n\nexport interface ExecutionFlow {\n entryPoint: string;\n entryPointKind: string;\n entryPointFile: string;\n criticality: number;\n hops: FlowHop[];\n}\n\n/**\n * Detect entry points: symbols that are likely execution starting points.\n * - Route nodes\n * - Functions with zero incoming call edges\n * - Symbols matching known entry patterns (main, handler, controller, etc.)\n */\nexport function detectEntryPoints(db: GraphDatabase, limit = 20): Array<{ id: string; name: string; kind: string; filePath: string; line: number }> {\n const rawDb = db.getRawDb();\n\n // 1. Route nodes are always entry points\n const routes = rawDb.all(\n `SELECT id, name, kind, file_path as filePath, start_line as line FROM nodes WHERE kind = 'route' LIMIT ?`,\n [limit]\n ) as any[];\n\n // 2. Functions/methods with no incoming call edges (graph roots)\n const roots = rawDb.all(\n `SELECT n.id, n.name, n.kind, n.file_path as filePath, n.start_line as line\n FROM nodes n\n WHERE n.kind IN ('function', 'method')\n AND n.is_exported = 1\n AND NOT EXISTS (\n SELECT 1 FROM edges e WHERE e.target = n.id AND e.kind = 'calls'\n )\n ORDER BY (SELECT COUNT(*) FROM edges e2 WHERE e2.source = n.id) DESC\n LIMIT ?`,\n [limit]\n ) as any[];\n\n // 3. Known entry point patterns\n const patterns = rawDb.all(\n `SELECT id, name, kind, file_path as filePath, start_line as line FROM nodes\n WHERE (lower(name) LIKE '%handler%' OR lower(name) LIKE '%controller%'\n OR lower(name) = 'main' OR lower(name) LIKE '%middleware%'\n OR lower(name) LIKE '%endpoint%')\n AND kind IN ('function', 'method', 'class')\n LIMIT ?`,\n [limit]\n ) as any[];\n\n // Deduplicate by id\n const seen = new Set<string>();\n const results: Array<{ id: string; name: string; kind: string; filePath: string; line: number }> = [];\n for (const entry of [...routes, ...roots, ...patterns]) {\n if (!seen.has(entry.id)) {\n seen.add(entry.id);\n results.push(entry);\n }\n }\n\n return results.slice(0, limit);\n}\n\n/**\n * Trace a single execution flow from an entry point forward through call edges.\n * Returns the chain of hops with criticality scoring.\n */\nexport function traceFlow(db: GraphDatabase, entryPointId: string, maxDepth = 10): FlowHop[] {\n const rawDb = db.getRawDb();\n const hops: FlowHop[] = [];\n const visited = new Set<string>();\n\n function walk(nodeId: string, depth: number): void {\n if (depth >= maxDepth || visited.has(nodeId)) return;\n visited.add(nodeId);\n\n const node = rawDb.get(\n 'SELECT name, kind, file_path as filePath, start_line as line FROM nodes WHERE id = ?',\n [nodeId]\n ) as any;\n if (!node) return;\n\n const edgeInfo = depth === 0 ? undefined : rawDb.get(\n `SELECT kind, confidence FROM edges WHERE target = ? AND source IN (${[...visited].map(() => '?').join(',')}) LIMIT 1`,\n [nodeId, ...[...visited]]\n ) as any;\n\n hops.push({\n symbol: node.name,\n kind: node.kind,\n filePath: node.filePath,\n line: node.line,\n edgeKind: edgeInfo?.kind,\n confidence: edgeInfo?.confidence,\n });\n\n // Follow outgoing call edges, ordered by target's fan-out (criticality)\n const callees = rawDb.all(\n `SELECT e.target, e.kind as edgeKind, e.confidence\n FROM edges e\n WHERE e.source = ? AND e.kind = 'calls'\n ORDER BY (SELECT COUNT(*) FROM edges e2 WHERE e2.source = e.target) DESC\n LIMIT 5`,\n [nodeId]\n ) as any[];\n\n for (const callee of callees) {\n walk(callee.target, depth + 1);\n }\n }\n\n walk(entryPointId, 0);\n return hops;\n}\n\n/**\n * Compute criticality score for a flow based on:\n * - Length (longer flows = more critical paths)\n * - Fan-out of hops (more downstream = higher criticality)\n * - Whether it touches I/O-like patterns (db, http, file)\n */\nexport function scoreCriticality(hops: FlowHop[]): number {\n if (hops.length === 0) return 0;\n\n const lengthScore = Math.min(hops.length / 10, 1.0); // normalize to 0-1\n\n const ioPatterns = /db|database|query|http|fetch|request|file|write|read|socket|stream/i;\n const touchesIO = hops.some(h => ioPatterns.test(h.symbol));\n const ioScore = touchesIO ? 0.3 : 0;\n\n return Math.min(lengthScore * 0.7 + ioScore, 1.0);\n}\n\n/**\n * Get execution flows from all detected entry points.\n */\nexport function getExecutionFlows(db: GraphDatabase, opts?: { maxFlows?: number; maxDepth?: number }): ExecutionFlow[] {\n const maxFlows = opts?.maxFlows ?? 15;\n const maxDepth = opts?.maxDepth ?? 10;\n\n const entryPoints = detectEntryPoints(db, maxFlows * 2);\n const flows: ExecutionFlow[] = [];\n\n for (const ep of entryPoints) {\n const hops = traceFlow(db, ep.id, maxDepth);\n if (hops.length < 2) continue; // Skip trivial flows (single node)\n\n const criticality = scoreCriticality(hops);\n flows.push({\n entryPoint: ep.name,\n entryPointKind: ep.kind,\n entryPointFile: ep.filePath,\n criticality,\n hops,\n });\n }\n\n // Sort by criticality descending\n flows.sort((a, b) => b.criticality - a.criticality);\n return flows.slice(0, maxFlows);\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }