@backthread/extractor 0.1.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 (379) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +83 -0
  3. package/dist/cluster/domain-grouping.d.ts +113 -0
  4. package/dist/cluster/domain-grouping.d.ts.map +1 -0
  5. package/dist/cluster/domain-grouping.js +277 -0
  6. package/dist/cluster/domain-grouping.js.map +1 -0
  7. package/dist/cluster/grouping-gate.d.ts +54 -0
  8. package/dist/cluster/grouping-gate.d.ts.map +1 -0
  9. package/dist/cluster/grouping-gate.js +0 -0
  10. package/dist/cluster/grouping-gate.js.map +1 -0
  11. package/dist/cluster/louvain.d.ts +88 -0
  12. package/dist/cluster/louvain.d.ts.map +1 -0
  13. package/dist/cluster/louvain.js +674 -0
  14. package/dist/cluster/louvain.js.map +1 -0
  15. package/dist/cluster/overrides.d.ts +19 -0
  16. package/dist/cluster/overrides.d.ts.map +1 -0
  17. package/dist/cluster/overrides.js +32 -0
  18. package/dist/cluster/overrides.js.map +1 -0
  19. package/dist/cluster/subsystem.d.ts +45 -0
  20. package/dist/cluster/subsystem.d.ts.map +1 -0
  21. package/dist/cluster/subsystem.js +299 -0
  22. package/dist/cluster/subsystem.js.map +1 -0
  23. package/dist/cluster/workspaces.d.ts +64 -0
  24. package/dist/cluster/workspaces.d.ts.map +1 -0
  25. package/dist/cluster/workspaces.js +739 -0
  26. package/dist/cluster/workspaces.js.map +1 -0
  27. package/dist/extract.d.ts +52 -0
  28. package/dist/extract.d.ts.map +1 -0
  29. package/dist/extract.js +48 -0
  30. package/dist/extract.js.map +1 -0
  31. package/dist/framework/celery/celery.d.ts +17 -0
  32. package/dist/framework/celery/celery.d.ts.map +1 -0
  33. package/dist/framework/celery/celery.js +524 -0
  34. package/dist/framework/celery/celery.js.map +1 -0
  35. package/dist/framework/contribute-step.d.ts +38 -0
  36. package/dist/framework/contribute-step.d.ts.map +1 -0
  37. package/dist/framework/contribute-step.js +403 -0
  38. package/dist/framework/contribute-step.js.map +1 -0
  39. package/dist/framework/detect-step.d.ts +8 -0
  40. package/dist/framework/detect-step.d.ts.map +1 -0
  41. package/dist/framework/detect-step.js +54 -0
  42. package/dist/framework/detect-step.js.map +1 -0
  43. package/dist/framework/detect-util.d.ts +24 -0
  44. package/dist/framework/detect-util.d.ts.map +1 -0
  45. package/dist/framework/detect-util.js +59 -0
  46. package/dist/framework/detect-util.js.map +1 -0
  47. package/dist/framework/django/django.d.ts +22 -0
  48. package/dist/framework/django/django.d.ts.map +1 -0
  49. package/dist/framework/django/django.js +940 -0
  50. package/dist/framework/django/django.js.map +1 -0
  51. package/dist/framework/fastapi/fastapi.d.ts +27 -0
  52. package/dist/framework/fastapi/fastapi.d.ts.map +1 -0
  53. package/dist/framework/fastapi/fastapi.js +477 -0
  54. package/dist/framework/fastapi/fastapi.js.map +1 -0
  55. package/dist/framework/faststream/faststream.d.ts +19 -0
  56. package/dist/framework/faststream/faststream.d.ts.map +1 -0
  57. package/dist/framework/faststream/faststream.js +765 -0
  58. package/dist/framework/faststream/faststream.js.map +1 -0
  59. package/dist/framework/flask/flask.d.ts +17 -0
  60. package/dist/framework/flask/flask.d.ts.map +1 -0
  61. package/dist/framework/flask/flask.js +507 -0
  62. package/dist/framework/flask/flask.js.map +1 -0
  63. package/dist/framework/graphql/graphql.d.ts +17 -0
  64. package/dist/framework/graphql/graphql.d.ts.map +1 -0
  65. package/dist/framework/graphql/graphql.js +708 -0
  66. package/dist/framework/graphql/graphql.js.map +1 -0
  67. package/dist/framework/grpc/grpc.d.ts +22 -0
  68. package/dist/framework/grpc/grpc.d.ts.map +1 -0
  69. package/dist/framework/grpc/grpc.js +618 -0
  70. package/dist/framework/grpc/grpc.js.map +1 -0
  71. package/dist/framework/litestar/litestar.d.ts +17 -0
  72. package/dist/framework/litestar/litestar.d.ts.map +1 -0
  73. package/dist/framework/litestar/litestar.js +536 -0
  74. package/dist/framework/litestar/litestar.js.map +1 -0
  75. package/dist/framework/nest/nest.d.ts +19 -0
  76. package/dist/framework/nest/nest.d.ts.map +1 -0
  77. package/dist/framework/nest/nest.js +613 -0
  78. package/dist/framework/nest/nest.js.map +1 -0
  79. package/dist/framework/next/next.d.ts +22 -0
  80. package/dist/framework/next/next.d.ts.map +1 -0
  81. package/dist/framework/next/next.js +449 -0
  82. package/dist/framework/next/next.js.map +1 -0
  83. package/dist/framework/node/node.d.ts +24 -0
  84. package/dist/framework/node/node.d.ts.map +1 -0
  85. package/dist/framework/node/node.js +1009 -0
  86. package/dist/framework/node/node.js.map +1 -0
  87. package/dist/framework/orchestrator/orchestrator.d.ts +34 -0
  88. package/dist/framework/orchestrator/orchestrator.d.ts.map +1 -0
  89. package/dist/framework/orchestrator/orchestrator.js +691 -0
  90. package/dist/framework/orchestrator/orchestrator.js.map +1 -0
  91. package/dist/framework/orm/orm.d.ts +61 -0
  92. package/dist/framework/orm/orm.d.ts.map +1 -0
  93. package/dist/framework/orm/orm.js +620 -0
  94. package/dist/framework/orm/orm.js.map +1 -0
  95. package/dist/framework/python/analyze.d.ts +38 -0
  96. package/dist/framework/python/analyze.d.ts.map +1 -0
  97. package/dist/framework/python/analyze.js +98 -0
  98. package/dist/framework/python/analyze.js.map +1 -0
  99. package/dist/framework/python/py-ast.d.ts +130 -0
  100. package/dist/framework/python/py-ast.d.ts.map +1 -0
  101. package/dist/framework/python/py-ast.js +344 -0
  102. package/dist/framework/python/py-ast.js.map +1 -0
  103. package/dist/framework/python-orm/python-orm.d.ts +19 -0
  104. package/dist/framework/python-orm/python-orm.d.ts.map +1 -0
  105. package/dist/framework/python-orm/python-orm.js +516 -0
  106. package/dist/framework/python-orm/python-orm.js.map +1 -0
  107. package/dist/framework/react-native/react-native.d.ts +35 -0
  108. package/dist/framework/react-native/react-native.d.ts.map +1 -0
  109. package/dist/framework/react-native/react-native.js +1181 -0
  110. package/dist/framework/react-native/react-native.js.map +1 -0
  111. package/dist/framework/register.d.ts +2 -0
  112. package/dist/framework/register.d.ts.map +1 -0
  113. package/dist/framework/register.js +59 -0
  114. package/dist/framework/register.js.map +1 -0
  115. package/dist/framework/registry.d.ts +31 -0
  116. package/dist/framework/registry.d.ts.map +1 -0
  117. package/dist/framework/registry.js +70 -0
  118. package/dist/framework/registry.js.map +1 -0
  119. package/dist/framework/routing/expo-router.d.ts +31 -0
  120. package/dist/framework/routing/expo-router.d.ts.map +1 -0
  121. package/dist/framework/routing/expo-router.js +356 -0
  122. package/dist/framework/routing/expo-router.js.map +1 -0
  123. package/dist/framework/routing/index.d.ts +4 -0
  124. package/dist/framework/routing/index.d.ts.map +1 -0
  125. package/dist/framework/routing/index.js +16 -0
  126. package/dist/framework/routing/index.js.map +1 -0
  127. package/dist/framework/routing/next-router.d.ts +45 -0
  128. package/dist/framework/routing/next-router.d.ts.map +1 -0
  129. package/dist/framework/routing/next-router.js +378 -0
  130. package/dist/framework/routing/next-router.js.map +1 -0
  131. package/dist/framework/routing/route-tree.d.ts +73 -0
  132. package/dist/framework/routing/route-tree.d.ts.map +1 -0
  133. package/dist/framework/routing/route-tree.js +120 -0
  134. package/dist/framework/routing/route-tree.js.map +1 -0
  135. package/dist/framework/types.d.ts +230 -0
  136. package/dist/framework/types.d.ts.map +1 -0
  137. package/dist/framework/types.js +25 -0
  138. package/dist/framework/types.js.map +1 -0
  139. package/dist/graph/cross-language.d.ts +11 -0
  140. package/dist/graph/cross-language.d.ts.map +1 -0
  141. package/dist/graph/cross-language.js +123 -0
  142. package/dist/graph/cross-language.js.map +1 -0
  143. package/dist/graph/extract.d.ts +13 -0
  144. package/dist/graph/extract.d.ts.map +1 -0
  145. package/dist/graph/extract.js +79 -0
  146. package/dist/graph/extract.js.map +1 -0
  147. package/dist/graph/file-graph.d.ts +186 -0
  148. package/dist/graph/file-graph.d.ts.map +1 -0
  149. package/dist/graph/file-graph.js +427 -0
  150. package/dist/graph/file-graph.js.map +1 -0
  151. package/dist/graph/http-callsites.d.ts +14 -0
  152. package/dist/graph/http-callsites.d.ts.map +1 -0
  153. package/dist/graph/http-callsites.js +107 -0
  154. package/dist/graph/http-callsites.js.map +1 -0
  155. package/dist/graph/incremental.d.ts +122 -0
  156. package/dist/graph/incremental.d.ts.map +1 -0
  157. package/dist/graph/incremental.js +448 -0
  158. package/dist/graph/incremental.js.map +1 -0
  159. package/dist/graph/language.d.ts +31 -0
  160. package/dist/graph/language.d.ts.map +1 -0
  161. package/dist/graph/language.js +146 -0
  162. package/dist/graph/language.js.map +1 -0
  163. package/dist/graph/noise-filter.d.ts +46 -0
  164. package/dist/graph/noise-filter.d.ts.map +1 -0
  165. package/dist/graph/noise-filter.js +199 -0
  166. package/dist/graph/noise-filter.js.map +1 -0
  167. package/dist/graph/python-adapter.d.ts +36 -0
  168. package/dist/graph/python-adapter.d.ts.map +1 -0
  169. package/dist/graph/python-adapter.js +402 -0
  170. package/dist/graph/python-adapter.js.map +1 -0
  171. package/dist/graph/python-manifest.d.ts +22 -0
  172. package/dist/graph/python-manifest.d.ts.map +1 -0
  173. package/dist/graph/python-manifest.js +137 -0
  174. package/dist/graph/python-manifest.js.map +1 -0
  175. package/dist/graph/python-stdlib.d.ts +2 -0
  176. package/dist/graph/python-stdlib.d.ts.map +1 -0
  177. package/dist/graph/python-stdlib.js +53 -0
  178. package/dist/graph/python-stdlib.js.map +1 -0
  179. package/dist/graph/ts-morph-adapter.d.ts +65 -0
  180. package/dist/graph/ts-morph-adapter.d.ts.map +1 -0
  181. package/dist/graph/ts-morph-adapter.js +265 -0
  182. package/dist/graph/ts-morph-adapter.js.map +1 -0
  183. package/dist/graph/types.d.ts +37 -0
  184. package/dist/graph/types.d.ts.map +1 -0
  185. package/dist/graph/types.js +50 -0
  186. package/dist/graph/types.js.map +1 -0
  187. package/dist/index.d.ts +45 -0
  188. package/dist/index.d.ts.map +1 -0
  189. package/dist/index.js +51 -0
  190. package/dist/index.js.map +1 -0
  191. package/dist/infra/aws/aws-parse.d.ts +39 -0
  192. package/dist/infra/aws/aws-parse.d.ts.map +1 -0
  193. package/dist/infra/aws/aws-parse.js +149 -0
  194. package/dist/infra/aws/aws-parse.js.map +1 -0
  195. package/dist/infra/aws/aws.d.ts +6 -0
  196. package/dist/infra/aws/aws.d.ts.map +1 -0
  197. package/dist/infra/aws/aws.js +425 -0
  198. package/dist/infra/aws/aws.js.map +1 -0
  199. package/dist/infra/azure/azure-parse.d.ts +73 -0
  200. package/dist/infra/azure/azure-parse.d.ts.map +1 -0
  201. package/dist/infra/azure/azure-parse.js +178 -0
  202. package/dist/infra/azure/azure-parse.js.map +1 -0
  203. package/dist/infra/azure/azure.d.ts +12 -0
  204. package/dist/infra/azure/azure.d.ts.map +1 -0
  205. package/dist/infra/azure/azure.js +673 -0
  206. package/dist/infra/azure/azure.js.map +1 -0
  207. package/dist/infra/cloudflare/cloudflare.d.ts +50 -0
  208. package/dist/infra/cloudflare/cloudflare.d.ts.map +1 -0
  209. package/dist/infra/cloudflare/cloudflare.js +382 -0
  210. package/dist/infra/cloudflare/cloudflare.js.map +1 -0
  211. package/dist/infra/cloudflare/wrangler-parse.d.ts +6 -0
  212. package/dist/infra/cloudflare/wrangler-parse.d.ts.map +1 -0
  213. package/dist/infra/cloudflare/wrangler-parse.js +278 -0
  214. package/dist/infra/cloudflare/wrangler-parse.js.map +1 -0
  215. package/dist/infra/compose/compose-parse.d.ts +24 -0
  216. package/dist/infra/compose/compose-parse.d.ts.map +1 -0
  217. package/dist/infra/compose/compose-parse.js +77 -0
  218. package/dist/infra/compose/compose-parse.js.map +1 -0
  219. package/dist/infra/compose/compose.d.ts +12 -0
  220. package/dist/infra/compose/compose.d.ts.map +1 -0
  221. package/dist/infra/compose/compose.js +201 -0
  222. package/dist/infra/compose/compose.js.map +1 -0
  223. package/dist/infra/convex/convex-parse.d.ts +28 -0
  224. package/dist/infra/convex/convex-parse.d.ts.map +1 -0
  225. package/dist/infra/convex/convex-parse.js +74 -0
  226. package/dist/infra/convex/convex-parse.js.map +1 -0
  227. package/dist/infra/convex/convex.d.ts +18 -0
  228. package/dist/infra/convex/convex.d.ts.map +1 -0
  229. package/dist/infra/convex/convex.js +199 -0
  230. package/dist/infra/convex/convex.js.map +1 -0
  231. package/dist/infra/digitalocean/digitalocean.d.ts +33 -0
  232. package/dist/infra/digitalocean/digitalocean.d.ts.map +1 -0
  233. package/dist/infra/digitalocean/digitalocean.js +204 -0
  234. package/dist/infra/digitalocean/digitalocean.js.map +1 -0
  235. package/dist/infra/firebase/firebase.d.ts +43 -0
  236. package/dist/infra/firebase/firebase.d.ts.map +1 -0
  237. package/dist/infra/firebase/firebase.js +271 -0
  238. package/dist/infra/firebase/firebase.js.map +1 -0
  239. package/dist/infra/fly/fly-parse.d.ts +52 -0
  240. package/dist/infra/fly/fly-parse.d.ts.map +1 -0
  241. package/dist/infra/fly/fly-parse.js +114 -0
  242. package/dist/infra/fly/fly-parse.js.map +1 -0
  243. package/dist/infra/fly/fly.d.ts +15 -0
  244. package/dist/infra/fly/fly.d.ts.map +1 -0
  245. package/dist/infra/fly/fly.js +265 -0
  246. package/dist/infra/fly/fly.js.map +1 -0
  247. package/dist/infra/gcp/gcp-parse.d.ts +24 -0
  248. package/dist/infra/gcp/gcp-parse.d.ts.map +1 -0
  249. package/dist/infra/gcp/gcp-parse.js +123 -0
  250. package/dist/infra/gcp/gcp-parse.js.map +1 -0
  251. package/dist/infra/gcp/gcp.d.ts +10 -0
  252. package/dist/infra/gcp/gcp.d.ts.map +1 -0
  253. package/dist/infra/gcp/gcp.js +502 -0
  254. package/dist/infra/gcp/gcp.js.map +1 -0
  255. package/dist/infra/heroku/heroku-parse.d.ts +33 -0
  256. package/dist/infra/heroku/heroku-parse.d.ts.map +1 -0
  257. package/dist/infra/heroku/heroku-parse.js +63 -0
  258. package/dist/infra/heroku/heroku-parse.js.map +1 -0
  259. package/dist/infra/heroku/heroku.d.ts +24 -0
  260. package/dist/infra/heroku/heroku.d.ts.map +1 -0
  261. package/dist/infra/heroku/heroku.js +253 -0
  262. package/dist/infra/heroku/heroku.js.map +1 -0
  263. package/dist/infra/image-resolve.d.ts +56 -0
  264. package/dist/infra/image-resolve.d.ts.map +1 -0
  265. package/dist/infra/image-resolve.js +229 -0
  266. package/dist/infra/image-resolve.js.map +1 -0
  267. package/dist/infra/infra-step.d.ts +39 -0
  268. package/dist/infra/infra-step.d.ts.map +1 -0
  269. package/dist/infra/infra-step.js +57 -0
  270. package/dist/infra/infra-step.js.map +1 -0
  271. package/dist/infra/k8s/index.d.ts +78 -0
  272. package/dist/infra/k8s/index.d.ts.map +1 -0
  273. package/dist/infra/k8s/index.js +251 -0
  274. package/dist/infra/k8s/index.js.map +1 -0
  275. package/dist/infra/kamal/kamal-parse.d.ts +23 -0
  276. package/dist/infra/kamal/kamal-parse.d.ts.map +1 -0
  277. package/dist/infra/kamal/kamal-parse.js +66 -0
  278. package/dist/infra/kamal/kamal-parse.js.map +1 -0
  279. package/dist/infra/kamal/kamal.d.ts +17 -0
  280. package/dist/infra/kamal/kamal.d.ts.map +1 -0
  281. package/dist/infra/kamal/kamal.js +162 -0
  282. package/dist/infra/kamal/kamal.js.map +1 -0
  283. package/dist/infra/netlify/netlify.d.ts +33 -0
  284. package/dist/infra/netlify/netlify.d.ts.map +1 -0
  285. package/dist/infra/netlify/netlify.js +247 -0
  286. package/dist/infra/netlify/netlify.js.map +1 -0
  287. package/dist/infra/opentofu/opentofu.d.ts +3 -0
  288. package/dist/infra/opentofu/opentofu.d.ts.map +1 -0
  289. package/dist/infra/opentofu/opentofu.js +157 -0
  290. package/dist/infra/opentofu/opentofu.js.map +1 -0
  291. package/dist/infra/pulumi/pulumi-parse.d.ts +60 -0
  292. package/dist/infra/pulumi/pulumi-parse.d.ts.map +1 -0
  293. package/dist/infra/pulumi/pulumi-parse.js +155 -0
  294. package/dist/infra/pulumi/pulumi-parse.js.map +1 -0
  295. package/dist/infra/pulumi/pulumi.d.ts +23 -0
  296. package/dist/infra/pulumi/pulumi.d.ts.map +1 -0
  297. package/dist/infra/pulumi/pulumi.js +260 -0
  298. package/dist/infra/pulumi/pulumi.js.map +1 -0
  299. package/dist/infra/railway/railway-parse.d.ts +54 -0
  300. package/dist/infra/railway/railway-parse.d.ts.map +1 -0
  301. package/dist/infra/railway/railway-parse.js +200 -0
  302. package/dist/infra/railway/railway-parse.js.map +1 -0
  303. package/dist/infra/railway/railway.d.ts +19 -0
  304. package/dist/infra/railway/railway.d.ts.map +1 -0
  305. package/dist/infra/railway/railway.js +397 -0
  306. package/dist/infra/railway/railway.js.map +1 -0
  307. package/dist/infra/register.d.ts +2 -0
  308. package/dist/infra/register.d.ts.map +1 -0
  309. package/dist/infra/register.js +81 -0
  310. package/dist/infra/register.js.map +1 -0
  311. package/dist/infra/registry.d.ts +64 -0
  312. package/dist/infra/registry.d.ts.map +1 -0
  313. package/dist/infra/registry.js +205 -0
  314. package/dist/infra/registry.js.map +1 -0
  315. package/dist/infra/relevance.d.ts +16 -0
  316. package/dist/infra/relevance.d.ts.map +1 -0
  317. package/dist/infra/relevance.js +132 -0
  318. package/dist/infra/relevance.js.map +1 -0
  319. package/dist/infra/render/render-parse.d.ts +76 -0
  320. package/dist/infra/render/render-parse.d.ts.map +1 -0
  321. package/dist/infra/render/render-parse.js +155 -0
  322. package/dist/infra/render/render-parse.js.map +1 -0
  323. package/dist/infra/render/render.d.ts +11 -0
  324. package/dist/infra/render/render.d.ts.map +1 -0
  325. package/dist/infra/render/render.js +303 -0
  326. package/dist/infra/render/render.js.map +1 -0
  327. package/dist/infra/sst/sst-parse.d.ts +25 -0
  328. package/dist/infra/sst/sst-parse.d.ts.map +1 -0
  329. package/dist/infra/sst/sst-parse.js +45 -0
  330. package/dist/infra/sst/sst-parse.js.map +1 -0
  331. package/dist/infra/sst/sst.d.ts +19 -0
  332. package/dist/infra/sst/sst.d.ts.map +1 -0
  333. package/dist/infra/sst/sst.js +236 -0
  334. package/dist/infra/sst/sst.js.map +1 -0
  335. package/dist/infra/supabase/supabase-parse.d.ts +34 -0
  336. package/dist/infra/supabase/supabase-parse.d.ts.map +1 -0
  337. package/dist/infra/supabase/supabase-parse.js +113 -0
  338. package/dist/infra/supabase/supabase-parse.js.map +1 -0
  339. package/dist/infra/supabase/supabase.d.ts +15 -0
  340. package/dist/infra/supabase/supabase.d.ts.map +1 -0
  341. package/dist/infra/supabase/supabase.js +198 -0
  342. package/dist/infra/supabase/supabase.js.map +1 -0
  343. package/dist/infra/terraform/hcl-parse.d.ts +34 -0
  344. package/dist/infra/terraform/hcl-parse.d.ts.map +1 -0
  345. package/dist/infra/terraform/hcl-parse.js +203 -0
  346. package/dist/infra/terraform/hcl-parse.js.map +1 -0
  347. package/dist/infra/terraform/terraform.d.ts +14 -0
  348. package/dist/infra/terraform/terraform.d.ts.map +1 -0
  349. package/dist/infra/terraform/terraform.js +264 -0
  350. package/dist/infra/terraform/terraform.js.map +1 -0
  351. package/dist/infra/types.d.ts +151 -0
  352. package/dist/infra/types.d.ts.map +1 -0
  353. package/dist/infra/types.js +14 -0
  354. package/dist/infra/types.js.map +1 -0
  355. package/dist/infra/vercel/vercel-parse.d.ts +70 -0
  356. package/dist/infra/vercel/vercel-parse.d.ts.map +1 -0
  357. package/dist/infra/vercel/vercel-parse.js +194 -0
  358. package/dist/infra/vercel/vercel-parse.js.map +1 -0
  359. package/dist/infra/vercel/vercel.d.ts +30 -0
  360. package/dist/infra/vercel/vercel.d.ts.map +1 -0
  361. package/dist/infra/vercel/vercel.js +523 -0
  362. package/dist/infra/vercel/vercel.js.map +1 -0
  363. package/dist/infra/walk.d.ts +36 -0
  364. package/dist/infra/walk.d.ts.map +1 -0
  365. package/dist/infra/walk.js +85 -0
  366. package/dist/infra/walk.js.map +1 -0
  367. package/dist/safety.d.ts +13 -0
  368. package/dist/safety.d.ts.map +1 -0
  369. package/dist/safety.js +67 -0
  370. package/dist/safety.js.map +1 -0
  371. package/dist/types.d.ts +47 -0
  372. package/dist/types.d.ts.map +1 -0
  373. package/dist/types.js +111 -0
  374. package/dist/types.js.map +1 -0
  375. package/dist/version.d.ts +2 -0
  376. package/dist/version.d.ts.map +1 -0
  377. package/dist/version.js +35 -0
  378. package/dist/version.js.map +1 -0
  379. package/package.json +65 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Backthread
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # @backthread/extractor
2
+
3
+ Deterministic, install-free **structural extraction** for TypeScript and Python
4
+ codebases. Point it at a working tree and it returns a structural graph of the
5
+ system — modules, edges, communities, god-nodes, framework roles, and
6
+ infrastructure — with **zero LLM, database, or network**.
7
+
8
+ It's the open, auditable structural core behind [Backthread](https://backthread.dev).
9
+ The extraction is exact and offline, so the same tree always yields the same
10
+ graph; it never executes the analyzed repo's code.
11
+
12
+ ## What it does
13
+
14
+ - **AST, install-free.** TypeScript via [ts-morph](https://ts-morph.com); Python
15
+ via Pyright's static analyzer under a no-filesystem-access host (never runs a
16
+ subprocess, never touches a virtualenv, never executes repo code). Import edges
17
+ are the backbone; call edges resolve through inferred types.
18
+ - **Polyglot.** A TS-frontend + Python-backend repo extracts as one merged graph,
19
+ with a coarse cross-language frontend→backend HTTP-API seam.
20
+ - **Communities + god-nodes.** Louvain community detection groups files into
21
+ modules; a statistical-outlier rule flags over-connected "god" modules.
22
+ - **Framework-aware.** A fleet of adapters (Next, Nest, React Native, an ORM
23
+ layer, and a Python fleet: FastAPI, Django, Flask, Litestar, Celery, SQLAlchemy,
24
+ gRPC, GraphQL, and more) contributes synthetic edges, role tags, and grouping
25
+ priors — deterministically, from parser output only.
26
+ - **Infra-aware.** Static readers for Cloudflare, Supabase, Terraform, and other
27
+ config surface deployment topology (workers, queues, datastores, …) without a
28
+ single API call.
29
+ - **Incremental.** A SHA-keyed file graph re-parses only changed files on
30
+ re-extraction.
31
+
32
+ ## Install
33
+
34
+ ```sh
35
+ npm install @backthread/extractor
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```ts
41
+ import { extract } from '@backthread/extractor';
42
+
43
+ const result = await extract('/path/to/repo');
44
+
45
+ console.log(result.cluster.modules); // modules with kinds, god-node flags, subsystems
46
+ console.log(result.cluster.moduleEdges); // structural edges between modules
47
+ console.log(result.infra); // deployment topology from config
48
+ console.log(result.frameworks); // detected framework stacks
49
+ ```
50
+
51
+ `extract()` is the one-shot convenience surface. Every stage is exported too, so
52
+ you can compose your own pipeline — run the incremental extractor, warm-start
53
+ clustering with a prior partition, or inject a resource-type classifier for
54
+ open-ended IaC:
55
+
56
+ ```ts
57
+ import {
58
+ extractGraph,
59
+ clusterGraph,
60
+ detectWorkspaceLayout,
61
+ contributeFrameworkGraph,
62
+ extractInfra,
63
+ } from '@backthread/extractor';
64
+
65
+ const graph = await extractGraph(repoDir);
66
+ const layout = detectWorkspaceLayout(repoDir);
67
+ const cluster = clusterGraph(graph, {}, { layout });
68
+ await contributeFrameworkGraph({ repoDir, graph, cluster });
69
+ const { graph: infra } = await extractInfra({ repoDir });
70
+ ```
71
+
72
+ ## Guarantees
73
+
74
+ - **No code execution.** Pure static analysis.
75
+ - **No network, no database, no LLM.** Extraction is fully offline and
76
+ deterministic. (You may optionally inject a `classifyResourceTypes` callback to
77
+ resolve unrecognized IaC resource types; without it, those keep a placeholder
78
+ kind.)
79
+ - **Stable output.** Same tree + same options → same graph.
80
+
81
+ ## License
82
+
83
+ MIT
@@ -0,0 +1,113 @@
1
+ export interface DomainGroup {
2
+ id: string;
3
+ name: string;
4
+ description?: string;
5
+ }
6
+ export interface ModuleAssignment {
7
+ groupId: string;
8
+ signature: string;
9
+ }
10
+ export interface GroupingModel {
11
+ groups: DomainGroup[];
12
+ assignments: Record<string, ModuleAssignment>;
13
+ }
14
+ export interface ProposedGroup {
15
+ name: string;
16
+ description?: string;
17
+ }
18
+ export interface LlmGrouping {
19
+ groups: ProposedGroup[];
20
+ assignments: Record<string, string>;
21
+ }
22
+ export interface ModuleSignal {
23
+ id: string;
24
+ summary: string;
25
+ whys: string[];
26
+ }
27
+ /**
28
+ * The per-module content SIGNATURE: a short hash of (summary + sorted decision
29
+ * ids + sorted changelog entry ids). It is the warm-start cache key — an
30
+ * unchanged signature means the module's semantic signal didn't materially move,
31
+ * so it keeps its cached group with NO LLM call. Sorted inputs make it
32
+ * order-independent; the slice keeps the cache JSON compact.
33
+ */
34
+ export declare function moduleSignature(input: {
35
+ summary: string;
36
+ decisionIds: readonly string[];
37
+ changelogIds: readonly string[];
38
+ }): string;
39
+ /**
40
+ * Mint a STABLE, unique group id from a display name (slugify + de-collide
41
+ * against an in-use set). An empty/garbage name falls back to `group`. The
42
+ * `taken` set is mutated to reserve the returned id.
43
+ *
44
+ * the id is `domain:`-NAMESPACED so a domain-group id can NEVER equal a
45
+ * module id (a bare path-derived slug — slugify strips ':'). The domain-pass
46
+ * overwrites measured modules' `subsystem` with these ids when the gate trips;
47
+ * React Flow keys both module nodes and subsystem super-nodes by id, so a bare
48
+ * `billing-money` group colliding with a `billing-money` module would corrupt its
49
+ * node store (the camera bug). The de-collision suffix is appended AFTER
50
+ * the namespaced base, so collisions stay namespaced too (`domain:foo-2`).
51
+ */
52
+ export declare function mintGroupId(name: string, taken: Set<string>): string;
53
+ /**
54
+ * MIGRATION: ensure every group id in a model is `domain:`-namespaced.
55
+ * A pre CACHED model (`subsystem_groups`) carries BARE ids that can equal
56
+ * a module id; the warm-start / cache-hit paths would otherwise carry those bare
57
+ * ids straight back onto the snapshots on a re-ingest. This maps each non-`domain:`
58
+ * id to `domain:<id>` (de-colliding against any already-namespaced id) and rewrites
59
+ * the assignments to match. Idempotent: an already-namespaced (or empty) model is
60
+ * returned unchanged. Only the OPAQUE id changes — display name/description and the
61
+ * member sets are untouched; the renderer treats subsystem ids opaquely and the
62
+ * uniform-apply rewrites every snapshot, so the one-time re-id is renderer-safe.
63
+ */
64
+ export declare function namespaceModelIds(model: GroupingModel): GroupingModel;
65
+ /**
66
+ * The WARM-START partition. Split the union of modules into:
67
+ * - `kept`: modules whose cached signature is unchanged AND whose cached group
68
+ * still exists → reuse the cached assignment, ZERO LLM.
69
+ * - `pendingIds`: new modules (no cache row) or modules whose signal changed →
70
+ * need (re)assignment by the LLM.
71
+ * With no cache, everything is pending (a first full pass).
72
+ */
73
+ export declare function selectPending(unionIds: readonly string[], signatures: Record<string, string>, cached: GroupingModel | null): {
74
+ kept: Record<string, ModuleAssignment>;
75
+ pendingIds: string[];
76
+ };
77
+ /**
78
+ * Build a model from a FULL LLM pass (every module assigned from scratch). Mints
79
+ * a stable id per proposed group and resolves every assignment to it.
80
+ */
81
+ export declare function buildFullModel(llm: LlmGrouping, signatures: Record<string, string>): GroupingModel;
82
+ /**
83
+ * Build a model from an INCREMENTAL pass: keep the prior groups + the `kept`
84
+ * assignments verbatim (existing modules NEVER move — the zero-churn guarantee),
85
+ * fold in any genuinely-new groups the LLM proposed, and assign the pending
86
+ * modules. A "new" group whose name matches an existing one reuses that id (the
87
+ * LLM just re-named an existing domain), so we don't duplicate it.
88
+ */
89
+ export declare function buildIncrementalModel(priorGroups: readonly DomainGroup[], kept: Record<string, ModuleAssignment>, llm: LlmGrouping, signatures: Record<string, string>): GroupingModel;
90
+ /**
91
+ * Carry stable group ids across a FULL re-cluster (the anti-drift safety valve).
92
+ * Greedily map each NEW group to the PRIOR group it overlaps most (by shared
93
+ * member count), carrying the prior id so a re-cluster doesn't rename/re-id a
94
+ * domain that's substantially the same set of modules — the
95
+ * `stabilizeModuleIds` warm-start precedent. New groups with no prior overlap
96
+ * keep their freshly-minted id (re-minted on collision with a carried id).
97
+ * Returns a NEW model; inputs are untouched.
98
+ */
99
+ export declare function reconcileGroupIds(next: GroupingModel, prior: GroupingModel): GroupingModel;
100
+ /**
101
+ * The finalize: DROP empty groups (an LLM-proposed group nobody landed
102
+ * in — a known Flash-Lite artifact) and ASSERT every module in `unionIds` is
103
+ * assigned to exactly one EXISTING group. Throws on any gap; the caller runs
104
+ * fail-soft, so a broken partition degrades to the directory default rather than
105
+ * persisting. Returns the pruned model.
106
+ */
107
+ export declare function finalizeModel(model: GroupingModel, unionIds: readonly string[]): GroupingModel;
108
+ export declare function groupToSubsystem(g: DomainGroup): {
109
+ id: string;
110
+ name: string;
111
+ description?: string;
112
+ };
113
+ //# sourceMappingURL=domain-grouping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-grouping.d.ts","sourceRoot":"","sources":["../../src/cluster/domain-grouping.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC/C;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAGD,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAKD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;CACjC,GAAG,MAAM,CAOT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAOpE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,CAqBrE;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,SAAS,MAAM,EAAE,EAC3B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,MAAM,EAAE,aAAa,GAAG,IAAI,GAC3B;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAAC,UAAU,EAAE,MAAM,EAAE,CAAA;CAAE,CAalE;AAmBD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,aAAa,CAWf;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,SAAS,WAAW,EAAE,EACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,EACtC,GAAG,EAAE,WAAW,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACjC,aAAa,CAgBf;AAWD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,aAAa,CAwD1F;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAsB9F;AAGD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,WAAW,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAEnG"}
@@ -0,0 +1,277 @@
1
+ // PURE helpers for the LLM domain-pass GROUPING MODEL: the per-repo
2
+ // { groups, assignments } artifact that is cached in `subsystem_groups` and
3
+ // applied UNIFORMLY to every snapshot (so the time slider never reshuffles a
4
+ // box). No I/O, no LLM here — just the deterministic glue the orchestration
5
+ // (decisions/subsystem-grouping.ts) and its tests share:
6
+ //
7
+ // * content SIGNATURES (the warm-start cache key),
8
+ // * stable group-id minting,
9
+ // * the warm-start PARTITION (which modules can keep their cached group vs
10
+ // which need (re)assignment),
11
+ // * building the model from a FULL or INCREMENTAL LLM reply,
12
+ // * member-overlap id RECONCILIATION (carry ids across a full re-cluster — the
13
+ // stabilizeModuleIds precedent), and
14
+ // * the TOTALITY finalize (drop empty groups + assert every module is
15
+ // in exactly one non-empty group).
16
+ import { createHash } from 'node:crypto';
17
+ import { slugify } from './overrides.js';
18
+ import { DOMAIN_SUBSYSTEM_PREFIX } from './subsystem.js';
19
+ /**
20
+ * The per-module content SIGNATURE: a short hash of (summary + sorted decision
21
+ * ids + sorted changelog entry ids). It is the warm-start cache key — an
22
+ * unchanged signature means the module's semantic signal didn't materially move,
23
+ * so it keeps its cached group with NO LLM call. Sorted inputs make it
24
+ * order-independent; the slice keeps the cache JSON compact.
25
+ */
26
+ export function moduleSignature(input) {
27
+ const canonical = JSON.stringify({
28
+ s: input.summary ?? '',
29
+ d: [...input.decisionIds].sort(),
30
+ c: [...input.changelogIds].sort(),
31
+ });
32
+ return createHash('sha256').update(canonical).digest('hex').slice(0, 16);
33
+ }
34
+ /**
35
+ * Mint a STABLE, unique group id from a display name (slugify + de-collide
36
+ * against an in-use set). An empty/garbage name falls back to `group`. The
37
+ * `taken` set is mutated to reserve the returned id.
38
+ *
39
+ * the id is `domain:`-NAMESPACED so a domain-group id can NEVER equal a
40
+ * module id (a bare path-derived slug — slugify strips ':'). The domain-pass
41
+ * overwrites measured modules' `subsystem` with these ids when the gate trips;
42
+ * React Flow keys both module nodes and subsystem super-nodes by id, so a bare
43
+ * `billing-money` group colliding with a `billing-money` module would corrupt its
44
+ * node store (the camera bug). The de-collision suffix is appended AFTER
45
+ * the namespaced base, so collisions stay namespaced too (`domain:foo-2`).
46
+ */
47
+ export function mintGroupId(name, taken) {
48
+ const base = DOMAIN_SUBSYSTEM_PREFIX + (slugify(name) || 'group');
49
+ let id = base;
50
+ let n = 2;
51
+ while (taken.has(id))
52
+ id = `${base}-${n++}`;
53
+ taken.add(id);
54
+ return id;
55
+ }
56
+ /**
57
+ * MIGRATION: ensure every group id in a model is `domain:`-namespaced.
58
+ * A pre CACHED model (`subsystem_groups`) carries BARE ids that can equal
59
+ * a module id; the warm-start / cache-hit paths would otherwise carry those bare
60
+ * ids straight back onto the snapshots on a re-ingest. This maps each non-`domain:`
61
+ * id to `domain:<id>` (de-colliding against any already-namespaced id) and rewrites
62
+ * the assignments to match. Idempotent: an already-namespaced (or empty) model is
63
+ * returned unchanged. Only the OPAQUE id changes — display name/description and the
64
+ * member sets are untouched; the renderer treats subsystem ids opaquely and the
65
+ * uniform-apply rewrites every snapshot, so the one-time re-id is renderer-safe.
66
+ */
67
+ export function namespaceModelIds(model) {
68
+ if (model.groups.every((g) => g.id.startsWith(DOMAIN_SUBSYSTEM_PREFIX)))
69
+ return model;
70
+ // Reserve the ids already in the right namespace so a bare id can't collide onto one.
71
+ const taken = new Set(model.groups.filter((g) => g.id.startsWith(DOMAIN_SUBSYSTEM_PREFIX)).map((g) => g.id));
72
+ const remap = new Map(); // old bare id → namespaced id
73
+ const groups = model.groups.map((g) => {
74
+ if (g.id.startsWith(DOMAIN_SUBSYSTEM_PREFIX))
75
+ return g;
76
+ let id = DOMAIN_SUBSYSTEM_PREFIX + g.id;
77
+ let n = 2;
78
+ while (taken.has(id))
79
+ id = `${DOMAIN_SUBSYSTEM_PREFIX}${g.id}-${n++}`;
80
+ taken.add(id);
81
+ remap.set(g.id, id);
82
+ return { ...g, id };
83
+ });
84
+ const assignments = {};
85
+ for (const [moduleId, a] of Object.entries(model.assignments)) {
86
+ assignments[moduleId] = { groupId: remap.get(a.groupId) ?? a.groupId, signature: a.signature };
87
+ }
88
+ return { groups, assignments };
89
+ }
90
+ /**
91
+ * The WARM-START partition. Split the union of modules into:
92
+ * - `kept`: modules whose cached signature is unchanged AND whose cached group
93
+ * still exists → reuse the cached assignment, ZERO LLM.
94
+ * - `pendingIds`: new modules (no cache row) or modules whose signal changed →
95
+ * need (re)assignment by the LLM.
96
+ * With no cache, everything is pending (a first full pass).
97
+ */
98
+ export function selectPending(unionIds, signatures, cached) {
99
+ const kept = {};
100
+ const pendingIds = [];
101
+ const groupIds = new Set((cached?.groups ?? []).map((g) => g.id));
102
+ for (const id of unionIds) {
103
+ const c = cached?.assignments[id];
104
+ if (c && c.signature === signatures[id] && groupIds.has(c.groupId)) {
105
+ kept[id] = c;
106
+ }
107
+ else {
108
+ pendingIds.push(id);
109
+ }
110
+ }
111
+ return { kept, pendingIds };
112
+ }
113
+ // Resolve LLM assignments (moduleId → group NAME) to {groupId, signature} via a
114
+ // name→id map. A module whose chosen name doesn't resolve is left unassigned —
115
+ // finalizeModel's totality assert is the single fail-loud gate for that, so we
116
+ // never silently invent a group here.
117
+ function resolveAssignments(llmAssignments, nameToId, signatures, into) {
118
+ for (const [moduleId, groupName] of Object.entries(llmAssignments)) {
119
+ const groupId = nameToId.get(groupName);
120
+ if (!groupId)
121
+ continue;
122
+ into[moduleId] = { groupId, signature: signatures[moduleId] ?? '' };
123
+ }
124
+ }
125
+ /**
126
+ * Build a model from a FULL LLM pass (every module assigned from scratch). Mints
127
+ * a stable id per proposed group and resolves every assignment to it.
128
+ */
129
+ export function buildFullModel(llm, signatures) {
130
+ const taken = new Set();
131
+ const nameToId = new Map();
132
+ const groups = llm.groups.map((g) => {
133
+ const id = mintGroupId(g.name, taken);
134
+ nameToId.set(g.name, id);
135
+ return g.description ? { id, name: g.name, description: g.description } : { id, name: g.name };
136
+ });
137
+ const assignments = {};
138
+ resolveAssignments(llm.assignments, nameToId, signatures, assignments);
139
+ return { groups, assignments };
140
+ }
141
+ /**
142
+ * Build a model from an INCREMENTAL pass: keep the prior groups + the `kept`
143
+ * assignments verbatim (existing modules NEVER move — the zero-churn guarantee),
144
+ * fold in any genuinely-new groups the LLM proposed, and assign the pending
145
+ * modules. A "new" group whose name matches an existing one reuses that id (the
146
+ * LLM just re-named an existing domain), so we don't duplicate it.
147
+ */
148
+ export function buildIncrementalModel(priorGroups, kept, llm, signatures) {
149
+ const taken = new Set(priorGroups.map((g) => g.id));
150
+ const nameToId = new Map();
151
+ for (const g of priorGroups)
152
+ nameToId.set(g.name, g.id);
153
+ const groups = [...priorGroups];
154
+ for (const g of llm.groups) {
155
+ if (nameToId.has(g.name))
156
+ continue; // re-proposed existing domain — reuse id
157
+ const id = mintGroupId(g.name, taken);
158
+ nameToId.set(g.name, id);
159
+ groups.push(g.description ? { id, name: g.name, description: g.description } : { id, name: g.name });
160
+ }
161
+ const assignments = { ...kept };
162
+ resolveAssignments(llm.assignments, nameToId, signatures, assignments);
163
+ return { groups, assignments };
164
+ }
165
+ /** Members (module ids) assigned to each group id, from a model's assignments. */
166
+ function membersByGroup(model) {
167
+ const out = new Map();
168
+ for (const [moduleId, a] of Object.entries(model.assignments)) {
169
+ (out.get(a.groupId) ?? out.set(a.groupId, new Set()).get(a.groupId)).add(moduleId);
170
+ }
171
+ return out;
172
+ }
173
+ /**
174
+ * Carry stable group ids across a FULL re-cluster (the anti-drift safety valve).
175
+ * Greedily map each NEW group to the PRIOR group it overlaps most (by shared
176
+ * member count), carrying the prior id so a re-cluster doesn't rename/re-id a
177
+ * domain that's substantially the same set of modules — the
178
+ * `stabilizeModuleIds` warm-start precedent. New groups with no prior overlap
179
+ * keep their freshly-minted id (re-minted on collision with a carried id).
180
+ * Returns a NEW model; inputs are untouched.
181
+ */
182
+ export function reconcileGroupIds(next, prior) {
183
+ const nextMembers = membersByGroup(next);
184
+ const priorMembers = membersByGroup(prior);
185
+ // All (nextId, priorId, overlap>0) pairs, strongest first.
186
+ const pairs = [];
187
+ for (const [nextId, nMembers] of nextMembers) {
188
+ for (const [priorId, pMembers] of priorMembers) {
189
+ let overlap = 0;
190
+ for (const m of nMembers)
191
+ if (pMembers.has(m))
192
+ overlap += 1;
193
+ if (overlap > 0)
194
+ pairs.push({ nextId, priorId, overlap });
195
+ }
196
+ }
197
+ pairs.sort((a, b) => b.overlap - a.overlap || (a.nextId < b.nextId ? -1 : 1));
198
+ const remap = new Map(); // nextId → priorId
199
+ const claimedPrior = new Set();
200
+ const claimedNext = new Set();
201
+ for (const { nextId, priorId } of pairs) {
202
+ if (claimedNext.has(nextId) || claimedPrior.has(priorId))
203
+ continue;
204
+ remap.set(nextId, priorId);
205
+ claimedNext.add(nextId);
206
+ claimedPrior.add(priorId);
207
+ }
208
+ // Reserve carried prior ids; re-mint any unmatched next id that would collide.
209
+ const taken = new Set(remap.values());
210
+ const finalIdFor = new Map();
211
+ for (const g of next.groups) {
212
+ const carried = remap.get(g.id);
213
+ if (carried) {
214
+ finalIdFor.set(g.id, carried);
215
+ continue;
216
+ }
217
+ // Unmatched: keep its own id unless a carried id already took it.
218
+ let id = g.id;
219
+ if (taken.has(id))
220
+ id = mintGroupId(g.name, taken);
221
+ else
222
+ taken.add(id);
223
+ finalIdFor.set(g.id, id);
224
+ }
225
+ // Carry the prior group's NAME/description for a matched group (id + label
226
+ // stay together so the carried box reads identically to before).
227
+ const priorById = new Map(prior.groups.map((g) => [g.id, g]));
228
+ const groups = next.groups.map((g) => {
229
+ const id = finalIdFor.get(g.id);
230
+ const carried = remap.has(g.id) ? priorById.get(id) : undefined;
231
+ const name = carried?.name ?? g.name;
232
+ const description = g.description ?? carried?.description;
233
+ return description ? { id, name, description } : { id, name };
234
+ });
235
+ const assignments = {};
236
+ for (const [moduleId, a] of Object.entries(next.assignments)) {
237
+ assignments[moduleId] = { groupId: finalIdFor.get(a.groupId) ?? a.groupId, signature: a.signature };
238
+ }
239
+ return { groups, assignments };
240
+ }
241
+ /**
242
+ * The finalize: DROP empty groups (an LLM-proposed group nobody landed
243
+ * in — a known Flash-Lite artifact) and ASSERT every module in `unionIds` is
244
+ * assigned to exactly one EXISTING group. Throws on any gap; the caller runs
245
+ * fail-soft, so a broken partition degrades to the directory default rather than
246
+ * persisting. Returns the pruned model.
247
+ */
248
+ export function finalizeModel(model, unionIds) {
249
+ const members = membersByGroup(model);
250
+ const groups = model.groups.filter((g) => (members.get(g.id)?.size ?? 0) > 0);
251
+ const liveIds = new Set(groups.map((g) => g.id));
252
+ const missing = [];
253
+ const dangling = [];
254
+ for (const id of unionIds) {
255
+ const a = model.assignments[id];
256
+ if (!a) {
257
+ missing.push(id);
258
+ }
259
+ else if (!liveIds.has(a.groupId)) {
260
+ dangling.push(id);
261
+ }
262
+ }
263
+ if (missing.length || dangling.length) {
264
+ const parts = [];
265
+ if (missing.length)
266
+ parts.push(`${missing.length} unassigned (${missing.slice(0, 5).join(', ')}…)`);
267
+ if (dangling.length)
268
+ parts.push(`${dangling.length} in a dropped/unknown group (${dangling.slice(0, 5).join(', ')}…)`);
269
+ throw new Error(`domain grouping is not a complete partition: ${parts.join('; ')}`);
270
+ }
271
+ return { groups, assignments: model.assignments };
272
+ }
273
+ // A group resolved to a Module.subsystem shape (id + name + optional description).
274
+ export function groupToSubsystem(g) {
275
+ return g.description ? { id: g.id, name: g.name, description: g.description } : { id: g.id, name: g.name };
276
+ }
277
+ //# sourceMappingURL=domain-grouping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domain-grouping.js","sourceRoot":"","sources":["../../src/cluster/domain-grouping.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ export declare const LAYER_NAMES: ReadonlySet<string>;
2
+ export declare const GATE_THRESHOLDS: {
3
+ readonly layerNamedFraction: 0.3;
4
+ readonly singletonBoxRatio: 0.35;
5
+ readonly godBucketRatio: 0.35;
6
+ };
7
+ export declare function isFrameworkSubsystemId(id: string | undefined): boolean;
8
+ /** One internal code module's gate input: its id + the file ids it owns (used
9
+ * only to derive the dominant directory box). `subsystemId` is the
10
+ * module's CURRENT subsystem id, if any: an adapter-namespaced one means the
11
+ * framework already grouped it, so the gate EXCLUDES it from the directory-
12
+ * quality measurement (optional + backward-compatible — absent ⇒ measured). */
13
+ export interface GateModule {
14
+ id: string;
15
+ fileIds: readonly string[];
16
+ subsystemId?: string;
17
+ }
18
+ export interface GroupingGateResult {
19
+ /** layerNamedFraction ≥ 0.30 OR singletonBoxRatio ≥ 0.35 OR godBucketRatio ≥ 0.35. */
20
+ trips: boolean;
21
+ /** Layer-named MODULES ÷ total internal modules. */
22
+ layerNamedFraction: number;
23
+ /** Singleton (1-module) BOXES ÷ total BOXES — the fragmentation signal. Note the
24
+ * BOX denominator (ratified against example-app: 3 singleton boxes of 8 →
25
+ * 0.375), distinct from the two module-denominator ratios. */
26
+ singletonBoxRatio: number;
27
+ /** Largest directory box size ÷ total internal MODULES (the mega-bucket smell;
28
+ * ratified against marola: 8/18 ≈ 0.44). */
29
+ godBucketRatio: number;
30
+ /** How many internal DIRECTORY-derived modules the gate ranged over (framework-
31
+ * grouped modules are excluded — see `frameworkExcluded`). */
32
+ internalCount: number;
33
+ /** how many framework-grouped (adapter-namespaced) modules were
34
+ * excluded from the measurement above. Surfaced so the orchestration can log
35
+ * the pin/skip (no silent caps) and audit why a framework-grouped repo didn't
36
+ * trip the LLM domain-pass. */
37
+ frameworkExcluded: number;
38
+ /** Human-readable threshold(s) that tripped — persisted to the cache `gate`
39
+ * column + logged, so we can always audit WHY a repo did/didn't get the lens. */
40
+ reasons: string[];
41
+ }
42
+ /**
43
+ * Evaluate the three directory-quality ratios over a repo's internal modules.
44
+ *
45
+ * Each module is bucketed by its dominant top-level directory. A ROOT-LEVEL
46
+ * module (no top-level dir at all — `dominantTopLevelDir` returns null) gets its
47
+ * OWN unique box, so it reads as a singleton and is never merged with other
48
+ * root files — which is correct: a loose root module is exactly the un-grouped
49
+ * smell the gate is meant to detect.
50
+ *
51
+ * An empty input never trips (there is nothing to group).
52
+ */
53
+ export declare function evaluateGroupingGate(modules: ReadonlyArray<GateModule>): GroupingGateResult;
54
+ //# sourceMappingURL=grouping-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping-gate.d.ts","sourceRoot":"","sources":["../../src/cluster/grouping-gate.ts"],"names":[],"mappings":"AA+BA,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,CAG1C,CAAC;AAKH,eAAO,MAAM,eAAe;;;;CAIlB,CAAC;AAgBX,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGtE;AAED;;;;gFAIgF;AAChF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,sFAAsF;IACtF,KAAK,EAAE,OAAO,CAAC;IACf,oDAAoD;IACpD,kBAAkB,EAAE,MAAM,CAAC;IAC3B;;mEAE+D;IAC/D,iBAAiB,EAAE,MAAM,CAAC;IAC1B;iDAC6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB;mEAC+D;IAC/D,aAAa,EAAE,MAAM,CAAC;IACtB;;;oCAGgC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B;sFACkF;IAClF,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,aAAa,CAAC,UAAU,CAAC,GACjC,kBAAkB,CAoEpB"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grouping-gate.js","sourceRoot":"","sources":["../../src/cluster/grouping-gate.ts"],"names":[],"mappings":"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"}