@maycombhq/atticus 2.0.0-beta.10 → 2.0.0-beta.12

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 (235) hide show
  1. package/dist/bin.js +3 -3
  2. package/dist/{chunk-AY2IUF4K.js → chunk-22GLUHGE.js} +659 -73
  3. package/dist/{chunk-CIUHAHM6.js → chunk-2A24BNRZ.js} +8 -8
  4. package/dist/{chunk-2RX7PI2Y.js → chunk-2ELFEKOO.js} +4 -4
  5. package/dist/{chunk-QKEFZRHS.js → chunk-2P6IHSRO.js} +17 -17
  6. package/dist/chunk-2Q2YBAR5.js +40 -0
  7. package/dist/{chunk-7DUDLVFJ.js → chunk-2VQLFNBO.js} +20 -20
  8. package/dist/{chunk-E3Z67HRK.js → chunk-3256EDLL.js} +4 -4
  9. package/dist/{chunk-OIU657QQ.js → chunk-34BCKMBS.js} +4 -4
  10. package/dist/{chunk-UR7RMZ3R.js → chunk-34NWVIBC.js} +2 -2
  11. package/dist/{chunk-6VBXAGJX.js → chunk-36KD4OGC.js} +14 -14
  12. package/dist/{chunk-I7IWQIEB.js → chunk-3CFBU2O6.js} +4 -4
  13. package/dist/{chunk-OSGQW2Z6.js → chunk-3JLTN3Y7.js} +8 -8
  14. package/dist/{chunk-FOGG4AUR.js → chunk-3M7QBKKG.js} +25 -7
  15. package/dist/{chunk-UF7TAFJM.js → chunk-3RP34PYV.js} +18 -18
  16. package/dist/{chunk-YLAJAI2W.js → chunk-3ZKLWM5Y.js} +11 -11
  17. package/dist/{chunk-LTQANUDH.js → chunk-47HPZ34V.js} +25 -25
  18. package/dist/chunk-4BPROPGG.js +45 -0
  19. package/dist/{chunk-Y4BRGOJR.js → chunk-4G56W6H7.js} +13 -10
  20. package/dist/{chunk-YXJ4XOHF.js → chunk-4HIQ2FTI.js} +4 -4
  21. package/dist/{chunk-AJJK7GLO.js → chunk-4HTILEXW.js} +3 -3
  22. package/dist/{chunk-OJLRFGBP.js → chunk-4Q2PGM5T.js} +78 -15
  23. package/dist/{chunk-GR6YKM55.js → chunk-4RDW2X43.js} +108 -14
  24. package/dist/{chunk-23M2LUYM.js → chunk-4VOG5H2K.js} +1 -1
  25. package/dist/chunk-5CSZTVXH.js +34 -0
  26. package/dist/{chunk-65C57N7P.js → chunk-5FFMJMVH.js} +19 -19
  27. package/dist/{chunk-XNYNEEBR.js → chunk-5GGGAI5C.js} +18 -18
  28. package/dist/{chunk-IUD3ME4E.js → chunk-5H46QFSL.js} +4 -4
  29. package/dist/{chunk-KIHOIVST.js → chunk-5ION6STH.js} +3 -3
  30. package/dist/chunk-5M3CLAOV.js +39 -0
  31. package/dist/chunk-5OACMWWI.js +886 -0
  32. package/dist/{chunk-2HMWX4T6.js → chunk-6ENDKY52.js} +11 -11
  33. package/dist/{chunk-OS7PQ35Z.js → chunk-6FG7QKJC.js} +22 -22
  34. package/dist/{chunk-FEZE6NIA.js → chunk-6JV3YHRR.js} +18 -18
  35. package/dist/{chunk-WGZWR4RF.js → chunk-6ROZRBWH.js} +5 -5
  36. package/dist/{chunk-WARBF2KY.js → chunk-6S27MUQQ.js} +10 -6
  37. package/dist/{chunk-TZDSDDSV.js → chunk-72DY5NCN.js} +2 -2
  38. package/dist/chunk-76QVBNEM.js +37 -0
  39. package/dist/{chunk-N4QZJJVB.js → chunk-77UOXZVM.js} +5 -5
  40. package/dist/{chunk-LVGBKKSM.js → chunk-7AXMUE2U.js} +15 -15
  41. package/dist/{chunk-FJCFYKVO.js → chunk-7TEQF64E.js} +196 -76
  42. package/dist/{chunk-IDGSU7JF.js → chunk-7TH6I6TL.js} +9 -9
  43. package/dist/{chunk-ZONE6E3Z.js → chunk-7UKETVPW.js} +2 -2
  44. package/dist/{chunk-XKS6THI5.js → chunk-7VNEDDCC.js} +2 -2
  45. package/dist/{chunk-BMHGA7WD.js → chunk-A5GY2EWH.js} +12 -12
  46. package/dist/{chunk-E3JYO547.js → chunk-AEZ3EICK.js} +20 -20
  47. package/dist/{chunk-7F2RUWPU.js → chunk-ARLH2ZMD.js} +1 -1
  48. package/dist/{chunk-VKMTFIWS.js → chunk-AYVLEB55.js} +18 -18
  49. package/dist/chunk-B6X5PJSA.js +320 -0
  50. package/dist/{chunk-JMSEEBN4.js → chunk-BRCDEGNE.js} +1 -1
  51. package/dist/{chunk-67J3VZBA.js → chunk-BSVTNNUK.js} +5 -5
  52. package/dist/{chunk-3GTZ2OON.js → chunk-BTOGAUWX.js} +20 -11
  53. package/dist/{chunk-4SVJNVEE.js → chunk-BXBCMGIQ.js} +2 -0
  54. package/dist/chunk-BXP2Q4TD.js +48 -0
  55. package/dist/{chunk-XPEEICAO.js → chunk-BZRWJUB4.js} +15 -15
  56. package/dist/{chunk-MH5OCRUM.js → chunk-CH6LUQLD.js} +2 -2
  57. package/dist/{chunk-T6USVBEJ.js → chunk-CIIRPLI6.js} +5 -5
  58. package/dist/chunk-CJXM6SG4.js +339 -0
  59. package/dist/{chunk-5XDNUJ4P.js → chunk-CQD26SMZ.js} +4 -2
  60. package/dist/{chunk-7TGYNOXD.js → chunk-CW5SEPUT.js} +7 -7
  61. package/dist/{chunk-5KTOPOEP.js → chunk-CWSZP2LU.js} +25 -25
  62. package/dist/chunk-CXK27ZUY.js +32 -0
  63. package/dist/{chunk-YGKYFMSL.js → chunk-CXY4YDXS.js} +3 -3
  64. package/dist/{chunk-R64GLVBO.js → chunk-DDZZXVQ5.js} +10 -10
  65. package/dist/{chunk-7YYEKTYF.js → chunk-DGZXJO5I.js} +8 -8
  66. package/dist/{chunk-IV7BCWWN.js → chunk-DONCF2XC.js} +3 -3
  67. package/dist/{chunk-RRVT4MPS.js → chunk-DPNCAFMB.js} +18 -18
  68. package/dist/{chunk-UBWCUP3G.js → chunk-DQKNOHUZ.js} +2 -2
  69. package/dist/{chunk-NGPU2ARF.js → chunk-DW4BM73R.js} +1 -1
  70. package/dist/{chunk-PEF5OEMB.js → chunk-DWN7RSNQ.js} +4 -4
  71. package/dist/{chunk-KC5DROFC.js → chunk-DWYPYVPJ.js} +14 -14
  72. package/dist/{chunk-B7434AE2.js → chunk-E73QLYK7.js} +24 -3
  73. package/dist/{chunk-EX6ZXS5K.js → chunk-EE3UNC44.js} +4 -4
  74. package/dist/chunk-EJDZEK22.js +53 -0
  75. package/dist/{chunk-ISNZYKAS.js → chunk-ENZWVTTN.js} +21 -21
  76. package/dist/{chunk-ROTY5J2L.js → chunk-EREL3TQG.js} +1 -1
  77. package/dist/{chunk-ZZXF6OOJ.js → chunk-ESGIBN3S.js} +2 -2
  78. package/dist/{chunk-YGR6OCHQ.js → chunk-EU7VTBAI.js} +8 -14
  79. package/dist/chunk-F5GA6G3U.js +48 -0
  80. package/dist/{chunk-JAA53T23.js → chunk-F6FGIYPT.js} +20 -20
  81. package/dist/{chunk-NPCD54I7.js → chunk-FAET4BB6.js} +8 -5
  82. package/dist/{chunk-YPBQNJHA.js → chunk-FBFSTYAB.js} +8 -8
  83. package/dist/{chunk-OEI7LVRP.js → chunk-FEBYMFZA.js} +24 -24
  84. package/dist/chunk-FMV6IZ3P.js +54 -0
  85. package/dist/{chunk-F7UQR4ZX.js → chunk-FQ6IBYFC.js} +3 -3
  86. package/dist/{chunk-J5LHDJU4.js → chunk-FSJMFPA3.js} +7 -7
  87. package/dist/chunk-GFZ5MIQG.js +47 -0
  88. package/dist/{chunk-LK44ULGI.js → chunk-GHSVJNVL.js} +104 -11
  89. package/dist/{chunk-LRS573EX.js → chunk-GKPOCUQR.js} +12 -7
  90. package/dist/{chunk-LDKUC2QJ.js → chunk-GLSNVC67.js} +17 -17
  91. package/dist/{chunk-47QE246J.js → chunk-GMDOXWIS.js} +5 -5
  92. package/dist/{chunk-5MI2SEV5.js → chunk-GN5ZLSLD.js} +3 -3
  93. package/dist/{chunk-JQ7XQPQS.js → chunk-GUNBOZ75.js} +4 -4
  94. package/dist/{chunk-HHUFVJF7.js → chunk-GYS64N6F.js} +6 -6
  95. package/dist/{chunk-AKJTKMXU.js → chunk-HIQWJ6JZ.js} +5 -5
  96. package/dist/{chunk-6GNS32SI.js → chunk-HJ52XDST.js} +4 -4
  97. package/dist/{chunk-2KDSXJFJ.js → chunk-HJUEQERG.js} +34 -7
  98. package/dist/chunk-HKGQUOQ3.js +88 -0
  99. package/dist/chunk-HP32HUWR.js +41 -0
  100. package/dist/{chunk-R4TBNKKC.js → chunk-HY2VVVFZ.js} +1249 -610
  101. package/dist/{chunk-G5SFOH7P.js → chunk-I2PNEG3M.js} +38 -23
  102. package/dist/{chunk-Y5PZHS4K.js → chunk-INCECZ2E.js} +5 -5
  103. package/dist/{chunk-RK6MKKKP.js → chunk-ISXNWUG7.js} +1 -1
  104. package/dist/{chunk-73VPWF5R.js → chunk-ITJ7ST5E.js} +4 -4
  105. package/dist/{chunk-5IALSMZ2.js → chunk-J3VAFDEX.js} +14 -14
  106. package/dist/chunk-JGLZUQVN.js +29 -0
  107. package/dist/{chunk-5XN76FTF.js → chunk-JLIEAQP4.js} +5 -5
  108. package/dist/{chunk-MGVYVW7Q.js → chunk-JQG4VO47.js} +1 -1
  109. package/dist/chunk-JXXQHETS.js +130 -0
  110. package/dist/{chunk-APSVL2AI.js → chunk-KNGESBFW.js} +15 -15
  111. package/dist/{chunk-7UKVYFQ2.js → chunk-KUYA2E7M.js} +8 -8
  112. package/dist/{chunk-WLIIQ2A4.js → chunk-KY2ZHTBJ.js} +7 -7
  113. package/dist/{chunk-YPIEYQF4.js → chunk-L4UIKAWD.js} +6 -6
  114. package/dist/chunk-LDUJ6NIT.js +247 -0
  115. package/dist/{chunk-5YIBJXGB.js → chunk-LTLR4JZJ.js} +10 -10
  116. package/dist/{chunk-IZNSAEBX.js → chunk-MFRPLAOH.js} +2 -2
  117. package/dist/{chunk-6GWHKMQR.js → chunk-MH7UBG47.js} +4 -4
  118. package/dist/{chunk-4GZXS6S2.js → chunk-MLAACAES.js} +278 -17
  119. package/dist/{chunk-D3PO4DOZ.js → chunk-MMB2OHUY.js} +4 -2
  120. package/dist/{chunk-DDAHCPGA.js → chunk-MNCQ2GL7.js} +12 -12
  121. package/dist/{chunk-UYYN2IUZ.js → chunk-MNUZX67F.js} +6 -6
  122. package/dist/{chunk-YFSSNGLR.js → chunk-MQHYCS6A.js} +32 -29
  123. package/dist/{chunk-MKRBG5EF.js → chunk-MRLCNXXR.js} +1 -1
  124. package/dist/{chunk-BUYJL3GJ.js → chunk-NBQO75XT.js} +1 -1
  125. package/dist/{chunk-GXJVY6WT.js → chunk-NCONDPHH.js} +5 -5
  126. package/dist/{chunk-ZP4FJHR4.js → chunk-NHS55U7T.js} +18 -18
  127. package/dist/{chunk-CRE4BJHM.js → chunk-NL6XQZSV.js} +23 -23
  128. package/dist/{chunk-YVLMBAYE.js → chunk-NSJ6ZR2A.js} +3 -3
  129. package/dist/{chunk-XRO65C7V.js → chunk-NTNJNRHW.js} +8 -6
  130. package/dist/{chunk-FTV6I76U.js → chunk-NTTXTLCQ.js} +25 -25
  131. package/dist/chunk-NWL7XEQ4.js +37 -0
  132. package/dist/{chunk-CNKGYDMG.js → chunk-NWXY3B4R.js} +23 -23
  133. package/dist/{chunk-52R2YXP5.js → chunk-O5W4ECUY.js} +16 -16
  134. package/dist/{chunk-OGRWQ562.js → chunk-O6ILVBYB.js} +2 -2
  135. package/dist/{chunk-BJPMKJTL.js → chunk-OJAJXU65.js} +102 -2
  136. package/dist/{chunk-FZL2HNWP.js → chunk-OMH3I5BH.js} +3 -3
  137. package/dist/{chunk-MF7QH4AX.js → chunk-P6UJ22XR.js} +5 -5
  138. package/dist/{chunk-HE4ZQXZM.js → chunk-P76AW3PA.js} +309 -15
  139. package/dist/{chunk-GZ4TKR3Q.js → chunk-PCCPXWJC.js} +48 -139
  140. package/dist/{chunk-6TJCUYC5.js → chunk-PGFRXGHA.js} +3 -3
  141. package/dist/{chunk-NIXVDQVO.js → chunk-PJRMMWU4.js} +2 -2
  142. package/dist/{chunk-X4W4XXWP.js → chunk-PKJ3K3GM.js} +5 -5
  143. package/dist/{chunk-KM2FBM3T.js → chunk-PVW2N63M.js} +302 -55
  144. package/dist/{chunk-Y7KBQ4BD.js → chunk-Q55UP5EZ.js} +22 -22
  145. package/dist/{chunk-7URGP4DD.js → chunk-QAFMLBPF.js} +12 -12
  146. package/dist/{chunk-KIAI6PWL.js → chunk-QEZSA2O7.js} +17 -17
  147. package/dist/{chunk-PKCMRPPB.js → chunk-QJ3OX7OC.js} +33 -27
  148. package/dist/{chunk-6EDQE7GO.js → chunk-QL4VNY4U.js} +2 -2
  149. package/dist/{chunk-6JLPXDWN.js → chunk-QR65C3DV.js} +5 -5
  150. package/dist/{chunk-ILFKECGI.js → chunk-QXGOEP44.js} +4 -4
  151. package/dist/chunk-QY7RGTUP.js +326 -0
  152. package/dist/{chunk-PGKHJYOB.js → chunk-RA64IK43.js} +1 -1
  153. package/dist/{chunk-XB5RFZHH.js → chunk-RLJDYLID.js} +12 -12
  154. package/dist/{chunk-AWECWW5Y.js → chunk-RMLUZYEA.js} +13 -11
  155. package/dist/chunk-RSVBX6A3.js +54 -0
  156. package/dist/chunk-RZWZO2JQ.js +42 -0
  157. package/dist/chunk-S5LSDXV4.js +40 -0
  158. package/dist/{chunk-TM7LC37P.js → chunk-SAC6FNKR.js} +181 -117
  159. package/dist/{chunk-DPHCFZ7W.js → chunk-SCBU46AJ.js} +3 -3
  160. package/dist/{chunk-EZIUFEN6.js → chunk-SGNHNN3G.js} +12 -12
  161. package/dist/{chunk-XKZHAD6Y.js → chunk-SHAAGH3T.js} +15 -15
  162. package/dist/chunk-SK5OYWIY.js +122 -0
  163. package/dist/{chunk-FR7JPYBD.js → chunk-SNSFQ47W.js} +12 -12
  164. package/dist/{chunk-FV5YFR6I.js → chunk-SSL6JMPA.js} +9 -9
  165. package/dist/{chunk-XEG3FE2R.js → chunk-TA2ZNDYD.js} +1 -1
  166. package/dist/{chunk-JF2NSTFO.js → chunk-TEHH47TG.js} +3 -3
  167. package/dist/{chunk-W5OYJMBT.js → chunk-TEZSZ24W.js} +5 -5
  168. package/dist/{chunk-SS66Q4VE.js → chunk-TH526O6E.js} +12 -12
  169. package/dist/{chunk-R6B6XAKK.js → chunk-TIAPEYWI.js} +4 -4
  170. package/dist/chunk-TLCRIAU3.js +44 -0
  171. package/dist/{chunk-FMKKVWZD.js → chunk-TQYBXDVH.js} +2 -2
  172. package/dist/chunk-TV4CGNEY.js +43 -0
  173. package/dist/{chunk-QICFHVRW.js → chunk-TVSNWIAM.js} +8 -6
  174. package/dist/{chunk-CHC5FKTU.js → chunk-TWHZU36X.js} +1 -1
  175. package/dist/{chunk-BMCKL3VQ.js → chunk-TXV2AYZB.js} +24 -24
  176. package/dist/{chunk-577AJVRS.js → chunk-U25OX22K.js} +2039 -289
  177. package/dist/{chunk-7EKESFWV.js → chunk-U4NNG3ES.js} +11 -11
  178. package/dist/{chunk-XQ3YIV5R.js → chunk-U5T4A2QV.js} +6 -6
  179. package/dist/{chunk-2XM6PYQQ.js → chunk-UT5OA7KA.js} +43 -11
  180. package/dist/{chunk-BXIX7S7O.js → chunk-V3VCUSQ6.js} +15 -15
  181. package/dist/{chunk-4QUQEBFT.js → chunk-V5XV3JSP.js} +6 -6
  182. package/dist/{chunk-F7YL2RZ4.js → chunk-VF4VOPMB.js} +23 -23
  183. package/dist/{chunk-3QAKDIEU.js → chunk-VLDM4QZM.js} +23 -23
  184. package/dist/chunk-VP5H6DII.js +34 -0
  185. package/dist/{chunk-N3NBWIYQ.js → chunk-VRYQJZFL.js} +10 -9
  186. package/dist/{chunk-FQSRHTTC.js → chunk-VS6FS472.js} +15 -15
  187. package/dist/{chunk-YMOJD5BO.js → chunk-VTMIRRIZ.js} +3 -3
  188. package/dist/{chunk-4PJADZRR.js → chunk-VXSJKWB7.js} +16 -16
  189. package/dist/{chunk-MTAUZW2Z.js → chunk-WE5VMPUP.js} +216 -106
  190. package/dist/{chunk-ZE3P35DA.js → chunk-WEG7DY5K.js} +9 -9
  191. package/dist/{chunk-V2TH46ZY.js → chunk-WIF7A6JU.js} +12 -12
  192. package/dist/{chunk-GFXLPJWY.js → chunk-WM4N2L4T.js} +2 -2
  193. package/dist/{chunk-XIWYUQZQ.js → chunk-X64BFQ3R.js} +9 -9
  194. package/dist/{chunk-QWVBEK4P.js → chunk-XJRC3ZDI.js} +13 -13
  195. package/dist/{chunk-F2FOQLJ7.js → chunk-XVIVWG7B.js} +6 -6
  196. package/dist/{chunk-XTVDAHH2.js → chunk-Y3ZKT6IF.js} +5 -5
  197. package/dist/{chunk-62YMDXY6.js → chunk-YURIUFKF.js} +16 -16
  198. package/dist/{chunk-HKTUIMH4.js → chunk-YY2WGL6S.js} +3 -3
  199. package/dist/{chunk-BDEKREZH.js → chunk-Z2BA4NNR.js} +3 -3
  200. package/dist/{chunk-MTEBM4Y4.js → chunk-Z47YGBUY.js} +19 -12
  201. package/dist/chunk-Z4JSRKNR.js +41 -0
  202. package/dist/{chunk-G2E5MNYP.js → chunk-Z53ZB34U.js} +7 -7
  203. package/dist/{chunk-NNUASOAA.js → chunk-ZBOPIYOY.js} +12 -12
  204. package/dist/{chunk-7GB4ZRE2.js → chunk-ZBQCLKTH.js} +12 -12
  205. package/dist/chunk-ZGI7DNJ6.js +38 -0
  206. package/dist/{chunk-P3TKKBAH.js → chunk-ZPT4QX3J.js} +4 -4
  207. package/dist/chunk-ZS47PQ3O.js +41 -0
  208. package/dist/{chunk-PIVKU64W.js → chunk-ZTIMXVV5.js} +2 -2
  209. package/dist/{chunk-T4RTWMJD.js → chunk-ZYASEL7K.js} +5 -5
  210. package/dist/files.json +469 -417
  211. package/dist/packages/sdk/npm/index.js +2309 -1983
  212. package/dist/packages/ui/dist/assets/{elk-api-Mo5w5xCa.js → elk-api-D2NcYpUJ.js} +2 -2
  213. package/dist/packages/ui/dist/assets/{index-Bp3XhPHX.css → index-C0JEkXyN.css} +1 -1
  214. package/dist/packages/ui/dist/assets/index-CT7skl01.js +29 -0
  215. package/dist/packages/ui/dist/index.html +2 -2
  216. package/package.json +4 -4
  217. package/dist/chunk-26PLPSQW.js +0 -48
  218. package/dist/chunk-2G4DFUWJ.js +0 -43
  219. package/dist/chunk-2M6WXO73.js +0 -38
  220. package/dist/chunk-5F3RJCHB.js +0 -45
  221. package/dist/chunk-B2VSVN4P.js +0 -34
  222. package/dist/chunk-B3O52AUQ.js +0 -275
  223. package/dist/chunk-CITDNDIZ.js +0 -53
  224. package/dist/chunk-DAQBIK5G.js +0 -47
  225. package/dist/chunk-DZRQDNPT.js +0 -34
  226. package/dist/chunk-FLOEZA6K.js +0 -29
  227. package/dist/chunk-FNHSVBRA.js +0 -48
  228. package/dist/chunk-FPGVOSOG.js +0 -41
  229. package/dist/chunk-FZ2E5LGK.js +0 -54
  230. package/dist/chunk-HB6XSGI6.js +0 -131
  231. package/dist/chunk-HUZQDKQK.js +0 -48
  232. package/dist/chunk-L4VJ4ETL.js +0 -41
  233. package/dist/chunk-XPCWQXTY.js +0 -37
  234. package/dist/chunk-YIEOFHOL.js +0 -30
  235. package/dist/packages/ui/dist/assets/index-DM212ZbV.js +0 -29
@@ -7,18 +7,18 @@ import {
7
7
  featuresForScan,
8
8
  namingHint,
9
9
  syncSources
10
- } from "./chunk-6JLPXDWN.js";
10
+ } from "./chunk-QR65C3DV.js";
11
11
  import {
12
12
  dirSource,
13
13
  sameCommit,
14
14
  verifyFacts
15
- } from "./chunk-4GZXS6S2.js";
15
+ } from "./chunk-MLAACAES.js";
16
16
  import {
17
17
  scanInputs
18
- } from "./chunk-R4TBNKKC.js";
18
+ } from "./chunk-HY2VVVFZ.js";
19
19
  import {
20
20
  listIngestors
21
- } from "./chunk-NIXVDQVO.js";
21
+ } from "./chunk-PJRMMWU4.js";
22
22
  import {
23
23
  BUILT_IN_EXTRACTORS,
24
24
  MODEL_READERS,
@@ -33,12 +33,12 @@ import {
33
33
  runDialectTests,
34
34
  runFrameworkTests,
35
35
  unmodelledFrameworks
36
- } from "./chunk-UR7RMZ3R.js";
36
+ } from "./chunk-34NWVIBC.js";
37
37
  import {
38
38
  baseClonePath,
39
39
  changesSince,
40
40
  checkoutState
41
- } from "./chunk-PGKHJYOB.js";
41
+ } from "./chunk-RA64IK43.js";
42
42
  import {
43
43
  DEFAULT_IGNORES,
44
44
  configHash,
@@ -50,11 +50,11 @@ import {
50
50
  sandboxedExtractor,
51
51
  scanRepo,
52
52
  withParseCache
53
- } from "./chunk-MKRBG5EF.js";
53
+ } from "./chunk-MRLCNXXR.js";
54
54
  import {
55
55
  buildContextPack,
56
56
  toRunSummary
57
- } from "./chunk-5XDNUJ4P.js";
57
+ } from "./chunk-CQD26SMZ.js";
58
58
  import {
59
59
  AgentDefinition,
60
60
  DECLARED_CALLER,
@@ -69,8 +69,11 @@ import {
69
69
  REPO_TYPE_SCHEMA_VERSION,
70
70
  RecordId,
71
71
  SCAN_SETTINGS_SCHEMA_VERSION,
72
+ TARGETS_ANOTHER_LABEL,
72
73
  TARGETS_SPLIT_LABEL,
73
74
  TARGETS_STEP_ID,
75
+ TOPICS_OUTSIDE_LABEL,
76
+ TOPICS_STEP_ID,
74
77
  applyCurated,
75
78
  applyLinkEvidence,
76
79
  applySharedMaps,
@@ -101,6 +104,7 @@ import {
101
104
  joinGuessesOf,
102
105
  joinRecords,
103
106
  joinSharedMaps,
107
+ joinTerms,
104
108
  lineNamesField,
105
109
  lineNamesRoute,
106
110
  lineNamesWord,
@@ -126,14 +130,16 @@ import {
126
130
  stackHelpersOff,
127
131
  stripLinkEvidence,
128
132
  stripSharedMaps,
133
+ termGrantRecords,
129
134
  throwIfCancelled,
130
135
  toCanonicalYaml,
136
+ topicQuestionText,
131
137
  urlHostPort
132
- } from "./chunk-577AJVRS.js";
138
+ } from "./chunk-U25OX22K.js";
133
139
  import {
134
140
  SCHEMA_VERSION,
135
141
  writeFileAtomic
136
- } from "./chunk-D3PO4DOZ.js";
142
+ } from "./chunk-MMB2OHUY.js";
137
143
  import {
138
144
  __toESM
139
145
  } from "./chunk-TV45EUGM.js";
@@ -1484,6 +1490,332 @@ import { join as join6 } from "node:path";
1484
1490
 
1485
1491
  // packages/scanner/dist/facts-catalog.js
1486
1492
  import { createHash as createHash2 } from "node:crypto";
1493
+
1494
+ // packages/scanner/dist/target-suggest.js
1495
+ var TARGETS_MAX_SUGGESTED = 5;
1496
+ var TARGETS_ANOTHER = TARGETS_ANOTHER_LABEL;
1497
+ var TARGETS_NO_EVIDENCE = "no evidence; listed so you can pick it";
1498
+ var STOP = new Set("url uri base host client clients service services svc api apis http https rest endpoint endpoints impl java kt ts js py cs go src main test get post put delete patch the and for com www internal example config configs properties yaml yml env app apps application new call calls feign template web request requests response gateway proxy remote adapter port".split(" "));
1499
+ function nameWords(s) {
1500
+ if (!s)
1501
+ return [];
1502
+ return [
1503
+ ...new Set(s.replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length >= 3 && !STOP.has(w) && !/^v?\d+$/.test(w)).map((w) => w.length > 4 && w.endsWith("s") && !w.endsWith("ss") ? w.slice(0, -1) : w))
1504
+ ];
1505
+ }
1506
+ var segs = (p) => p.split(/[?#]/)[0].split("/").filter(Boolean).map((x) => /^[{:<$]/.test(x) ? "{}" : x);
1507
+ var sameSeg = (a, b) => a === "{}" || b === "{}" || a === b;
1508
+ var under = (path, prefix) => {
1509
+ const a = segs(prefix);
1510
+ const b = segs(path);
1511
+ return a.length > 0 && a.length <= b.length && a.every((x, i) => x === b[i]);
1512
+ };
1513
+ function serves(entry, call, bases) {
1514
+ const e = segs(entry);
1515
+ const tries = [
1516
+ segs(call),
1517
+ ...bases.filter((b) => under(call, b)).map((b) => segs(call).slice(segs(b).length))
1518
+ ];
1519
+ return tries.some((c) => c.length === e.length && c.every((x, i) => sameSeg(x, e[i])));
1520
+ }
1521
+ function clientOf(f) {
1522
+ const q = f.cite.quote ?? "";
1523
+ const named2 = /\b([A-Z][A-Za-z0-9]*(?:Client|Service|Api|Feign|Gateway|Proxy))\b/.exec(q)?.[1];
1524
+ if (named2)
1525
+ return named2;
1526
+ const file = f.cite.file.split("/").pop().replace(/\.[^.]+$/, "");
1527
+ return /(Client|Service|Api|Feign|Gateway|Proxy)$/.test(file) ? file : void 0;
1528
+ }
1529
+ function hostOf(f, facts) {
1530
+ const fromUrl = (u) => /^[a-z][a-z0-9+.-]*:\/\/([^/:?#]+)/i.exec(u)?.[1];
1531
+ if (f.host)
1532
+ return fromUrl(f.host) ?? f.host.split(/[/:]/)[0];
1533
+ if (f.base) {
1534
+ const cfg = facts.find((x) => x.kind === "config" && x.key === f.base && !!x.value);
1535
+ if (!cfg?.value)
1536
+ return void 0;
1537
+ return fromUrl(cfg.value) ?? (/^[a-z0-9-]+(\.[a-z0-9-]+)+(:\d+)?$/i.test(cfg.value) ? cfg.value.split(":")[0] : void 0);
1538
+ }
1539
+ return void 0;
1540
+ }
1541
+ var answerLabel = (q) => q.answer?.option !== void 0 ? q.options[q.answer.option - 1]?.label : q.answer?.text;
1542
+ var NOT_A_TARGET = /* @__PURE__ */ new Set(["None of these", TARGETS_SPLIT_LABEL, TARGETS_ANOTHER_LABEL]);
1543
+ function candidates(callerRepo, ctx) {
1544
+ const manifest = estateRepos(ctx.op).filter((r) => r.id !== callerRepo || !!ctx.only);
1545
+ const systems = ctx.op.profiles.flatMap((p) => p.profile?.systems ?? []);
1546
+ const reposOfSystem = /* @__PURE__ */ new Map();
1547
+ for (const r of estateRepos(ctx.op))
1548
+ if (r.system)
1549
+ reposOfSystem.set(r.system, (reposOfSystem.get(r.system) ?? 0) + 1);
1550
+ const read = new Set((ctx.estate ?? []).filter((x) => x.facts.length > 0).map((x) => x.repo));
1551
+ const repoOf = /* @__PURE__ */ new Map();
1552
+ for (const r of ctx.records)
1553
+ if (r.kind === "Component" && r.repo)
1554
+ repoOf.set(r.id, r.repo);
1555
+ if (!ctx.estate)
1556
+ for (const repo of repoOf.values())
1557
+ read.add(repo);
1558
+ const endpoints = ctx.records.filter((r) => r.kind === "Endpoint");
1559
+ const deploys = (ctx.estate ?? []).flatMap((x) => x.facts.filter((f) => f.kind === "deploy" && !!f.basePath));
1560
+ const out = [];
1561
+ for (const m of manifest) {
1562
+ const own2 = new Set([m.id, m.component, ...m.modules.map((x) => x.component)].filter((x) => !!x).map(factIdPart));
1563
+ const sys = m.system && reposOfSystem.get(m.system) === 1 ? systems.find((s) => s.id === m.system) : void 0;
1564
+ const names = /* @__PURE__ */ new Map();
1565
+ for (const n of [m.id, m.component, ...m.modules.map((x) => x.component)])
1566
+ for (const w of nameWords(n))
1567
+ if (!names.has(w))
1568
+ names.set(w, n);
1569
+ for (const a of sys ? [sys.id, ...sys.aliases] : [])
1570
+ for (const w of nameWords(a))
1571
+ if (!names.has(w))
1572
+ names.set(w, a);
1573
+ const bases = [];
1574
+ if (m.basePath)
1575
+ bases.push({ path: m.basePath, from: "the manifest's basePath" });
1576
+ for (const x of m.modules)
1577
+ if (x.basePath)
1578
+ bases.push({ path: x.basePath, from: `the basePath of its module ${x.component}` });
1579
+ for (const d of deploys) {
1580
+ const reaches = d.exposes ? factIdPart(d.exposes) : d.repo === m.id ? m.id : void 0;
1581
+ if (!reaches || !(own2.has(reaches) || d.repo === m.id && !d.exposes))
1582
+ continue;
1583
+ const what2 = d.platform === "apigee" ? "its proxy's BasePath" : `the ${d.resourceType ?? "route"} ${d.resourceName ?? d.id}`;
1584
+ bases.push({ path: d.basePath, from: `${what2} (${d.repo} ${d.cite.file}:${d.cite.line})` });
1585
+ }
1586
+ const comps = [
1587
+ ...new Set(endpoints.filter((e) => repoOf.get(e.component) === m.id).map((e) => e.component))
1588
+ ].sort();
1589
+ const isRead = read.has(m.id);
1590
+ const forLabel = comps.length ? comps : [m.id];
1591
+ for (const label2 of forLabel) {
1592
+ const mine = endpoints.filter((e) => e.component === label2);
1593
+ const entries = (ctx.estate ?? []).filter((x) => x.repo === m.id).flatMap((x) => x.facts.filter((f) => f.kind === "entry" && (!comps.length || factIdPart(f.component ?? m.component ?? m.id) === label2 || comps.length === 1))).map((f) => ({
1594
+ ...f.method ? { method: f.method.toUpperCase() } : {},
1595
+ path: f.path,
1596
+ at: `${f.cite.file}:${f.cite.line}`
1597
+ }));
1598
+ for (const e of mine)
1599
+ if (!entries.some((x) => x.path === e.pathOrTopic))
1600
+ entries.push({
1601
+ ...e.method ? { method: e.method.toUpperCase() } : {},
1602
+ path: e.pathOrTopic,
1603
+ at: e.id
1604
+ });
1605
+ out.push({
1606
+ s: { label: label2, kind: "repo", repo: m.id, read: isRead, score: 0, why: [] },
1607
+ names,
1608
+ bases,
1609
+ entries,
1610
+ ...m.description?.text ? { description: m.description.text } : {},
1611
+ hosts: m.hosts.map((h) => h.toLowerCase())
1612
+ });
1613
+ }
1614
+ }
1615
+ for (const c of ctx.only ?? [])
1616
+ if (!out.some((x) => x.s.label === c))
1617
+ out.push({
1618
+ s: {
1619
+ label: c,
1620
+ kind: "repo",
1621
+ repo: repoOf.get(c) ?? callerRepo,
1622
+ read: true,
1623
+ score: 0,
1624
+ why: []
1625
+ },
1626
+ names: /* @__PURE__ */ new Map(),
1627
+ bases: [],
1628
+ entries: [],
1629
+ hosts: []
1630
+ });
1631
+ const own = new Set(estateRepos(ctx.op).flatMap((r) => r.system ? [r.system] : []));
1632
+ const seen = /* @__PURE__ */ new Set();
1633
+ for (const s of systems) {
1634
+ if (!(s.boundary === "vendor" || !own.has(s.id)) || seen.has(s.id))
1635
+ continue;
1636
+ seen.add(s.id);
1637
+ const names = /* @__PURE__ */ new Map();
1638
+ for (const n of [s.id, s.name, ...s.aliases])
1639
+ for (const w of nameWords(n))
1640
+ if (!names.has(w))
1641
+ names.set(w, n);
1642
+ out.push({
1643
+ s: {
1644
+ label: s.id,
1645
+ kind: "outside",
1646
+ read: false,
1647
+ name: s.name,
1648
+ boundary: s.boundary,
1649
+ score: 0,
1650
+ why: []
1651
+ },
1652
+ names,
1653
+ bases: [],
1654
+ entries: [],
1655
+ hosts: s.aliases.map((a) => a.toLowerCase())
1656
+ });
1657
+ }
1658
+ return out;
1659
+ }
1660
+ function targetSuggestions(f, ctx) {
1661
+ const all = candidates(f.repo, ctx);
1662
+ const df = /* @__PURE__ */ new Map();
1663
+ for (const c of all)
1664
+ for (const w of c.names.keys())
1665
+ df.set(w, (df.get(w) ?? 0) + 1);
1666
+ const telling = (w) => (df.get(w) ?? 0) <= Math.max(2, Math.floor(all.length / 3));
1667
+ const host = hostOf(f, ctx.facts)?.toLowerCase();
1668
+ const client = clientOf(f);
1669
+ const said = [
1670
+ { from: f.base ? `the config key ${f.base}` : "", words: nameWords(f.base), weight: 4 },
1671
+ { from: client ? `the client ${client}` : "", words: nameWords(client), weight: 4 },
1672
+ {
1673
+ from: host ? `the host label ${host.split(".")[0]} (${host})` : "",
1674
+ words: host ? nameWords(host.split(".")[0]) : [],
1675
+ weight: 4
1676
+ },
1677
+ {
1678
+ from: `the path ${f.path}`,
1679
+ words: nameWords(segs(f.path).filter((x) => x !== "{}").join(" ")),
1680
+ weight: 2
1681
+ }
1682
+ ].filter((x) => x.from && x.words.length);
1683
+ const method = f.method?.toUpperCase();
1684
+ const earlier = (ctx.questions ?? []).filter((q) => q.askedBy?.step === TARGETS_STEP_ID && q.state === "answered" && q.repo === f.repo && !q.evidence.includes(`${f.cite.file}:${f.cite.line}`));
1685
+ const only = ctx.only ? new Set(ctx.only) : void 0;
1686
+ const out = [];
1687
+ for (const c of all) {
1688
+ if (only && c.s.kind === "repo" && !only.has(c.s.label))
1689
+ continue;
1690
+ const s = { ...c.s, why: [] };
1691
+ const add = (n, why) => {
1692
+ s.score += n;
1693
+ s.why.push(why);
1694
+ };
1695
+ if (only?.has(c.s.label))
1696
+ add(6, "the join found an entry of it that serves the call");
1697
+ const hit = c.entries.find((e) => (!method || !e.method || e.method === method || e.method === "ANY") && serves(e.path, f.path, c.bases.map((b) => b.path)));
1698
+ if (hit && !only) {
1699
+ const what2 = [hit.method, hit.path].filter(Boolean).join(" ");
1700
+ add(6, `serves ${what2} (${hit.at})`);
1701
+ s.serves = [what2];
1702
+ }
1703
+ const base2 = c.bases.find((b) => under(f.path, b.path));
1704
+ if (base2)
1705
+ add(5, `its basePath ${base2.path} matches: ${base2.from}`);
1706
+ if (host && c.hosts.includes(host))
1707
+ add(8, `it lists ${host} under hosts`);
1708
+ for (const x of said) {
1709
+ const w = x.words.find((y) => c.names.has(y) && telling(y));
1710
+ if (w)
1711
+ add(x.weight, `named like ${x.from}`);
1712
+ }
1713
+ if (c.description) {
1714
+ const d = new Set(nameWords(c.description));
1715
+ const w = said.flatMap((x) => x.words).find((y) => d.has(y) && telling(y));
1716
+ if (w)
1717
+ add(2, `its description mentions ${w}`);
1718
+ }
1719
+ const named2 = earlier.filter((q) => {
1720
+ const l = answerLabel(q);
1721
+ if (!l || NOT_A_TARGET.has(l))
1722
+ return false;
1723
+ const t = slugify(l);
1724
+ return t === slugify(c.s.label) || !!c.s.repo && t === slugify(c.s.repo);
1725
+ }).length;
1726
+ if (named2)
1727
+ add(3, `picked for ${named2} other ${named2 === 1 ? "call" : "calls"} of ${f.repo}`);
1728
+ if (!s.score)
1729
+ s.why.push(TARGETS_NO_EVIDENCE);
1730
+ s.why = [...new Set(s.why)];
1731
+ out.push(s);
1732
+ }
1733
+ return out.sort((a, b) => b.score - a.score || Number(b.read) - Number(a.read) || (a.kind === b.kind ? 0 : a.kind === "repo" ? -1 : 1) || a.label.localeCompare(b.label));
1734
+ }
1735
+ function offeredSuggestions(ranked, o) {
1736
+ const max = o.max ?? TARGETS_MAX_SUGGESTED;
1737
+ const strong = ranked.filter((s) => s.score >= 2);
1738
+ const fill = ranked.filter((s) => s.score < 2 && (s.kind === "outside" || s.read && o.serving.has(s.label)));
1739
+ return [...strong, ...fill].slice(0, max);
1740
+ }
1741
+ function targetPicker(op, read = /* @__PURE__ */ new Set()) {
1742
+ const repos = estateRepos(op).map((r) => ({
1743
+ id: r.id,
1744
+ kind: "repo",
1745
+ name: r.component && r.component !== r.id ? `${r.id} (${r.component})` : r.id,
1746
+ read: read.has(r.id)
1747
+ })).sort((a, b) => a.id.localeCompare(b.id));
1748
+ const seen = /* @__PURE__ */ new Set();
1749
+ const systems = op.profiles.flatMap((p) => p.profile?.systems ?? []).filter((s) => !seen.has(s.id) && !!seen.add(s.id)).map((s) => ({ id: s.id, kind: "system", name: s.name, boundary: s.boundary })).sort((a, b) => a.id.localeCompare(b.id));
1750
+ const owned = new Set(op.profiles.flatMap((p) => (p.profile?.systems ?? []).flatMap((s) => s.owner ? [s.owner] : [])));
1751
+ const teams = (op.roles?.teams ?? []).map((t) => {
1752
+ const name = t.name ?? t.id;
1753
+ const has = owned.has(t.id);
1754
+ return {
1755
+ id: t.id,
1756
+ kind: "team",
1757
+ name,
1758
+ ...has ? {} : {
1759
+ adds: {
1760
+ id: slugify(`${t.id}-system`),
1761
+ name: `${name}'s system`,
1762
+ boundary: "internal",
1763
+ owner: t.id
1764
+ }
1765
+ }
1766
+ };
1767
+ }).sort((a, b) => a.id.localeCompare(b.id));
1768
+ return [...repos, ...systems, ...teams];
1769
+ }
1770
+ function pickerLines(picks) {
1771
+ const of = (k) => picks.filter((p) => p.kind === k);
1772
+ return [
1773
+ `Repos (${of("repo").length}): ${of("repo").map((p) => `${p.id}${p.read ? "" : " (not read yet)"}`).join(", ") || "none"}`,
1774
+ `Systems (${of("system").length}): ${of("system").map((p) => `${p.id} (${p.boundary})`).join(", ") || "none"}`,
1775
+ `Teams (${of("team").length}): ${of("team").map((p) => `${p.id}${p.adds ? " (no system yet)" : ""}`).join(", ") || "none"}`
1776
+ ];
1777
+ }
1778
+ function topicQuestionDrafts(repo, records) {
1779
+ const out = /* @__PURE__ */ new Map();
1780
+ for (const r of records) {
1781
+ if (r.kind !== "Unresolved")
1782
+ continue;
1783
+ const x = r;
1784
+ if (x.unresolvedKind !== "event-publish" && x.unresolvedKind !== "event-subscribe")
1785
+ continue;
1786
+ const topic = String(x.raw);
1787
+ if (!topic || topic.includes("${") || /\s/.test(topic))
1788
+ continue;
1789
+ const ev = x.evidence.filter((e) => e.repo === repo && e.path && e.line && !/[\s:]/.test(e.path)).map((e) => `${e.path}:${e.line}`).sort();
1790
+ if (!ev.length)
1791
+ continue;
1792
+ const side = x.unresolvedKind === "event-publish" ? "publish" : "listen";
1793
+ const question = topicQuestionText(topic, x.owner ?? repo, side);
1794
+ const draft = {
1795
+ question,
1796
+ options: [
1797
+ {
1798
+ label: TOPICS_OUTSIDE_LABEL,
1799
+ means: `${topic} belongs to another team's system or a vendor's: name it, or the team, from the list`,
1800
+ changes: `${topic} is added under that system's topics in the profile (or the system is added, owner the team), as a file change for review; the next write ${side === "publish" ? "sends the publish to it" : "takes the listener's messages from it"}, marked as your word`
1801
+ },
1802
+ {
1803
+ label: "None of these",
1804
+ means: `Nothing outside the estate owns ${topic}, or a repo not read yet serves it`,
1805
+ changes: `It stays a loose end, and this isn't asked again`
1806
+ }
1807
+ ],
1808
+ evidence: [...new Set(ev)],
1809
+ scope: "repo"
1810
+ };
1811
+ const id = questionId({ step: TOPICS_STEP_ID, repo, question, evidence: draft.evidence });
1812
+ if (!out.has(id))
1813
+ out.set(id, { topic, id, draft });
1814
+ }
1815
+ return [...out.values()].sort((a, b) => a.topic.localeCompare(b.topic));
1816
+ }
1817
+
1818
+ // packages/scanner/dist/facts-catalog.js
1487
1819
  var TARGETS_STEP = TARGETS_STEP_ID;
1488
1820
  var TARGETS_NONE = "None of these";
1489
1821
  var byKindId = (a, b) => a.kind === b.kind ? a.id.localeCompare(b.id) : a.kind.localeCompare(b.kind);
@@ -1556,27 +1888,88 @@ function targetAsks(facts, records, asks) {
1556
1888
  }
1557
1889
  return { list, repoOf };
1558
1890
  }
1559
- var vendorsOf = (op) => outsideProfileSystems(op);
1560
1891
  var outsideAs = (s) => s.boundary === "vendor" ? "an outside system" : "another team's system";
1561
1892
  var callWhat = (f) => [f.method?.toUpperCase(), f.path].filter(Boolean).join(" ");
1562
- function targetQuestionDrafts(facts, records, op, asks) {
1563
- const { list, repoOf } = targetAsks(facts, records, asks);
1564
- const vendors = vendorsOf(op);
1565
- return list.map(({ f, q, servers }) => {
1566
- const what2 = callWhat(f);
1893
+ function suggestionWhy(s, prefix) {
1894
+ const served = s.serves ?? [];
1895
+ let why = s.why;
1896
+ if (prefix !== void 0 && served.length > 1) {
1897
+ const under2 = prefix === "/" ? "" : ` under ${prefix}`;
1898
+ why = [
1899
+ `serves ${served[0]} and ${served.length - 1} more${under2}`,
1900
+ ...why.filter((w) => !w.startsWith("serves "))
1901
+ ];
1902
+ }
1903
+ return (why.length ? why : [TARGETS_NO_EVIDENCE]).slice(0, 3).join("; ");
1904
+ }
1905
+ function suggestionOption(s, callerRepo, n, prefix) {
1906
+ const why = suggestionWhy(s, prefix);
1907
+ if (s.kind === "outside")
1908
+ return {
1909
+ label: s.label,
1910
+ means: `${s.name}, ${outsideAs({ boundary: s.boundary ?? "vendor" })}: ${why}`,
1911
+ changes: n ? `The ${n} calls go to ${s.name} when the facts are next written` : `The call goes to ${s.name} when the facts are next written`
1912
+ };
1913
+ const who = s.label === s.repo ? `${s.repo}${s.read ? "" : " (not read yet)"}` : `${s.label}, built in ${s.repo}${s.read ? "" : " (not read yet)"}`;
1914
+ const them = n ? `The ${n} calls` : "The call";
1915
+ return {
1916
+ label: s.label,
1917
+ means: `${who}: ${why}`,
1918
+ changes: s.read ? `${them} ${n ? "join" : "joins"} ${s.label} when the facts are next written (atticus verify ${callerRepo} --write)` : `${them} ${n ? "go" : "goes"} to ${s.repo} when the facts are next written (atticus verify ${callerRepo} --write), and ${n ? "join" : "joins"} its route once ${s.repo} is read and verified (/atticus-map ${s.repo}); if no route of it serves ${n ? "them" : "it"}, the question opens again`
1919
+ };
1920
+ }
1921
+ var anotherOption = (op) => {
1922
+ const repos = estateRepos(op).length;
1923
+ const systems = new Set(op.profiles.flatMap((p) => (p.profile?.systems ?? []).map((s) => s.id))).size;
1924
+ const teams = op.roles?.teams?.length ?? 0;
1925
+ return {
1926
+ label: TARGETS_ANOTHER,
1927
+ means: `A repo, system or team not listed here: the manifest's ${repos} repos (read or not), the profiles' ${systems} systems and the ${teams} teams in roles.yaml`,
1928
+ changes: "Nothing until you name one: atticus questions answer <id> --target <repo, system or team id> lists them and takes the one you name (the app's Questions page lists them too); naming a vendor or a team with no system adds that system to the profile for review"
1929
+ };
1930
+ };
1931
+ function offered(members, facts, records, op, asks, ctx) {
1932
+ const merged = /* @__PURE__ */ new Map();
1933
+ for (const m of members) {
1934
+ const ambiguous = asks?.some((a) => a.reason === "ambiguous" && a.call.repo === m.f.repo && a.call.fact === m.f.id);
1935
+ for (const s of targetSuggestions(m.f, {
1936
+ op,
1937
+ records,
1938
+ facts,
1939
+ ...ctx.estate ? { estate: ctx.estate } : {},
1940
+ ...ctx.questions ? { questions: ctx.questions } : {},
1941
+ ...ambiguous ? { only: m.servers } : {}
1942
+ })) {
1943
+ const x = merged.get(s.label);
1944
+ if (!x)
1945
+ merged.set(s.label, { ...s, why: [...s.why], serves: [...s.serves ?? []] });
1946
+ else {
1947
+ x.score += s.score;
1948
+ for (const w of s.why)
1949
+ if (!x.why.includes(w))
1950
+ x.why.push(w);
1951
+ for (const w of s.serves ?? [])
1952
+ if (!x.serves.includes(w))
1953
+ x.serves.push(w);
1954
+ if (x.why.length > 1)
1955
+ x.why = x.why.filter((w) => w !== TARGETS_NO_EVIDENCE);
1956
+ }
1957
+ }
1958
+ }
1959
+ const ranked = [...merged.values()].sort((a, b) => b.score - a.score || Number(b.read) - Number(a.read) || (a.kind === b.kind ? 0 : a.kind === "repo" ? -1 : 1) || a.label.localeCompare(b.label));
1960
+ const serving = new Set(members.flatMap((m) => m.servers));
1961
+ const types = new Set(members.flatMap((m) => SERVES[m.f.callType] ?? []));
1962
+ return offeredSuggestions(ranked, { types, serving });
1963
+ }
1964
+ function targetQuestionDrafts(facts, records, op, asks, ctx = {}) {
1965
+ const { list } = targetAsks(facts, records, asks);
1966
+ return list.map((m) => {
1967
+ const { f, q } = m;
1567
1968
  const draft = {
1568
1969
  question: q.question,
1569
1970
  options: [
1570
- ...servers.map((c) => ({
1571
- label: c,
1572
- means: `${c}${repoOf.get(c) ? `, built in ${repoOf.get(c)},` : ""} answers ${what2}`,
1573
- changes: `The call joins ${c} when the facts are next written (atticus verify ${f.repo} --write)`
1574
- })),
1575
- ...vendors.map((s) => ({
1576
- label: s.id,
1577
- means: `${s.name}, ${outsideAs(s)}, answers ${what2}`,
1578
- changes: `The call goes to ${s.name} when the facts are next written`
1579
- })),
1971
+ ...offered([m], facts, records, op, asks, ctx).map((s) => suggestionOption(s, f.repo)),
1972
+ anotherOption(op),
1580
1973
  {
1581
1974
  label: TARGETS_NONE,
1582
1975
  means: "Nothing in the estate or the org pack's systems answers it",
@@ -1622,28 +2015,51 @@ function groupVia(f) {
1622
2015
  return ` through ${f.base}`;
1623
2016
  return "";
1624
2017
  }
1625
- function targetGroupQuestion(repo, f) {
2018
+ function targetGroupQuestion(repo, f, facts) {
2019
+ const proxy = facts ? proxyOf(f, facts) : void 0;
2020
+ const through = f.base ?? f.host ?? f.to;
2021
+ if (proxy && through) {
2022
+ const p = targetPathPrefix(f.path);
2023
+ return `Which repo serves the routes under ${p === "/" ? "" : p}/** that ${proxy} forwards to ${through}?`;
2024
+ }
1626
2025
  return `Which repo or system answers the calls ${repo} makes under ${targetPathPrefix(f.path)}${groupVia(f)}?`;
1627
2026
  }
2027
+ function proxyOf(f, facts) {
2028
+ if (!f.from)
2029
+ return void 0;
2030
+ const from = facts.find((x) => x.id === f.from);
2031
+ if (!from || from.kind !== "entry")
2032
+ return void 0;
2033
+ const proxy = facts.find((x) => x.kind === "deploy" && x.repo === f.repo && x.platform === "apigee" && !!x.basePath);
2034
+ return proxy ? proxy.resourceName ?? f.repo : void 0;
2035
+ }
2036
+ function targetGroupWordings(repo, f, facts) {
2037
+ return [.../* @__PURE__ */ new Set([targetGroupQuestion(repo, f, facts), targetGroupQuestion(repo, f)])];
2038
+ }
2039
+ var repo0 = (members) => members[0].f.repo;
1628
2040
  var byLine = (a, b) => a.localeCompare(b, "en", { numeric: true });
1629
- var answerLabel = (q) => q.answer?.option !== void 0 ? q.options[q.answer.option - 1]?.label : q.answer?.text;
2041
+ var answerLabel2 = (q) => q.answer?.option !== void 0 ? q.options[q.answer.option - 1]?.label : q.answer?.text;
1630
2042
  function splitTargetGroups(questions) {
1631
- return new Set(questions.filter((q) => q.askedBy?.step === TARGETS_STEP && q.state === "answered" && answerLabel(q) === TARGETS_SPLIT).map((q) => q.question.trim()));
2043
+ return new Set(questions.filter((q) => q.askedBy?.step === TARGETS_STEP && q.state === "answered" && answerLabel2(q) === TARGETS_SPLIT).map((q) => q.question.trim()));
1632
2044
  }
1633
2045
  function groupedTargetDrafts(facts, records, op, asks, o) {
1634
- const { list, repoOf } = targetAsks(facts, records, asks);
1635
- const own = new Map(targetQuestionDrafts(facts, records, op, asks).map((d) => [d.factId, d]));
2046
+ const { list } = targetAsks(facts, records, asks);
2047
+ const ctx = {
2048
+ ...o.estate ? { estate: o.estate } : {},
2049
+ ...o.questions ? { questions: o.questions } : {}
2050
+ };
2051
+ const own = new Map(targetQuestionDrafts(facts, records, op, asks, ctx).map((d) => [d.factId, d]));
1636
2052
  const groups = /* @__PURE__ */ new Map();
1637
2053
  for (const a of list) {
1638
2054
  if (!o.ask.has(a.f.id))
1639
2055
  continue;
1640
- const k = targetGroupQuestion(a.f.repo, a.f);
2056
+ const k = targetGroupQuestion(a.f.repo, a.f, facts);
1641
2057
  groups.set(k, [...groups.get(k) ?? [], a]);
1642
2058
  }
1643
- const vendors = vendorsOf(op);
1644
2059
  const out = [];
1645
2060
  for (const [question, members] of groups) {
1646
- if (members.length === 1 || o.split?.has(question)) {
2061
+ const split = targetGroupWordings(repo0(members), members[0].f, facts).some((w) => o.split?.has(w));
2062
+ if (members.length === 1 || split) {
1647
2063
  for (const m of members)
1648
2064
  out.push({ ...own.get(m.f.id), factIds: [m.f.id] });
1649
2065
  continue;
@@ -1652,21 +2068,12 @@ function groupedTargetDrafts(facts, records, op, asks, o) {
1652
2068
  const whats = [...new Set(members.map((m) => callWhat(m.f)))];
1653
2069
  const listed = whats.length > 5 ? `${whats.slice(0, 5).join(", ")} and ${whats.length - 5} more` : whats.join(", ");
1654
2070
  const n = members.length;
1655
- const servers = [...new Set(members.flatMap((m) => m.servers))].sort();
1656
2071
  const evidence = [...new Set(members.flatMap((m) => m.q.evidence))].sort(byLine);
1657
2072
  const draft = {
1658
2073
  question,
1659
2074
  options: [
1660
- ...servers.map((c) => ({
1661
- label: c,
1662
- means: `${c}${repoOf.get(c) ? `, built in ${repoOf.get(c)},` : ""} answers all ${n} calls: ${listed}`,
1663
- changes: `The ${n} calls join ${c} when the facts are next written (atticus verify ${repo} --write)`
1664
- })),
1665
- ...vendors.map((s) => ({
1666
- label: s.id,
1667
- means: `${s.name}, ${outsideAs(s)}, answers all ${n} calls: ${listed}`,
1668
- changes: `The ${n} calls go to ${s.name} when the facts are next written`
1669
- })),
2075
+ ...offered(members, facts, records, op, asks, ctx).map((s) => suggestionOption(s, repo, n, targetPathPrefix(members[0].f.path))),
2076
+ anotherOption(op),
1670
2077
  {
1671
2078
  label: TARGETS_SPLIT,
1672
2079
  means: `The ${n} calls (${listed}) don't all go to one place`,
@@ -1691,6 +2098,40 @@ function groupedTargetDrafts(facts, records, op, asks, o) {
1691
2098
  }
1692
2099
  return out.sort((a, b) => a.factId.localeCompare(b.factId));
1693
2100
  }
2101
+ function targetRuleOffers(questions, factsOf) {
2102
+ const byKey = /* @__PURE__ */ new Map();
2103
+ for (const q of questions) {
2104
+ if (q.state !== "open" || q.askedBy?.step !== TARGETS_STEP)
2105
+ continue;
2106
+ const facts = factsOf(q.repo) ?? [];
2107
+ const at3 = new Set(q.evidence);
2108
+ const calls = facts.filter((f) => f.kind === "call" && f.repo === q.repo && at3.has(`${f.cite.file}:${f.cite.line}`));
2109
+ if (!calls.length)
2110
+ continue;
2111
+ const prefixes = new Set(calls.map((c) => targetPathPrefix(c.path)));
2112
+ const hosts = new Set(calls.map((c) => c.host?.replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").split(/[/:]/)[0]));
2113
+ const [prefix] = prefixes;
2114
+ const [host] = hosts;
2115
+ const match = prefixes.size === 1 && prefix !== "/" ? `${prefix}/**` : hosts.size === 1 && host ? host : void 0;
2116
+ if (!match)
2117
+ continue;
2118
+ const key = `${q.repo}
2119
+ ${match}`;
2120
+ const x = byKey.get(key) ?? { match, ids: [], calls: 0 };
2121
+ x.ids.push(q.id);
2122
+ x.calls += calls.length;
2123
+ byKey.set(key, x);
2124
+ }
2125
+ const out = /* @__PURE__ */ new Map();
2126
+ for (const x of byKey.values()) {
2127
+ if (x.ids.length < 2)
2128
+ continue;
2129
+ const ids = [...x.ids].sort();
2130
+ for (const id of ids)
2131
+ out.set(id, { match: x.match, ids, calls: x.calls });
2132
+ }
2133
+ return out;
2134
+ }
1694
2135
  var segmentsOf = (p) => p.split(/[?#]/)[0].split("/").filter(Boolean).map((x) => /^[{:<]/.test(x) ? "{}" : x);
1695
2136
  function ruleCoversCall(match, f, facts) {
1696
2137
  if (isPathMatch(match)) {
@@ -1711,7 +2152,7 @@ function ruledTargets(repo, facts, questions, o = {}) {
1711
2152
  if (!needsTarget(f, facts))
1712
2153
  continue;
1713
2154
  const q = rules.find((r) => ruleCoversCall(r.answer.match, f, facts));
1714
- const label2 = q ? answerLabel(q) : void 0;
2155
+ const label2 = q ? answerLabel2(q) : void 0;
1715
2156
  if (q && label2 && label2 !== TARGETS_SPLIT)
1716
2157
  out.set(f.id, { id: q.id, match: q.answer.match, label: label2 });
1717
2158
  }
@@ -1732,13 +2173,13 @@ function targetsFromAnswers(repo, facts, questions, o = {}) {
1732
2173
  continue;
1733
2174
  let asked = byId.get(questionId({ step: TARGETS_STEP, repo, ...q }));
1734
2175
  if (!asked || asked.state !== "answered" || !asked.answer) {
1735
- const g = groups.get(targetGroupQuestion(repo, f));
2176
+ const g = targetGroupWordings(repo, f, facts).map((w) => groups.get(w)).find((x) => !!x);
1736
2177
  asked = g && (needsTarget(f, facts) || g.evidence.includes(q.evidence[0])) ? g : void 0;
1737
2178
  }
1738
- let label2 = asked && asked.state === "answered" && asked.answer ? answerLabel(asked) : void 0;
1739
- if (!label2 || label2 === TARGETS_SPLIT)
2179
+ let label2 = asked && asked.state === "answered" && asked.answer ? answerLabel2(asked) : void 0;
2180
+ if (!label2 || label2 === TARGETS_SPLIT || label2 === TARGETS_ANOTHER)
1740
2181
  label2 = ruled.get(f.id)?.label;
1741
- if (!label2 || label2 === TARGETS_SPLIT)
2182
+ if (!label2 || label2 === TARGETS_SPLIT || label2 === TARGETS_ANOTHER)
1742
2183
  continue;
1743
2184
  if (label2 === TARGETS_NONE) {
1744
2185
  out[f.id] = NO_TARGET;
@@ -1750,6 +2191,23 @@ function targetsFromAnswers(repo, facts, questions, o = {}) {
1750
2191
  }
1751
2192
  return out;
1752
2193
  }
2194
+ function answeredQuestionOfCall(repo, facts, questions, factId) {
2195
+ const f = facts.find((x) => x.id === factId);
2196
+ if (!f || f.kind !== "call")
2197
+ return void 0;
2198
+ const own = targetQuestionFor(f);
2199
+ const ownId = questionId({ step: TARGETS_STEP, repo, ...own });
2200
+ const answered = questions.filter((q2) => q2.askedBy?.step === TARGETS_STEP && q2.state === "answered" && q2.repo === repo);
2201
+ const q = answered.find((x) => x.id === ownId) ?? answered.find((x) => targetGroupWordings(repo, f, facts).includes(x.question.trim()) && x.evidence.includes(own.evidence[0]));
2202
+ return q?.answer?.match ? void 0 : q;
2203
+ }
2204
+ function answerReconfirmed(q) {
2205
+ if (!q.answer || !q.reopened)
2206
+ return false;
2207
+ const now2 = answerLabel2(q);
2208
+ const was = answerLabel2({ ...q, answer: q.reopened.answer });
2209
+ return !!now2 && !!was && slugify(now2) === slugify(was);
2210
+ }
1753
2211
  var JOINED_BY = {
1754
2212
  named: "the call names it",
1755
2213
  repo: "the call names its repo",
@@ -1763,7 +2221,7 @@ function callsOfTargetQuestion(repo, facts, q) {
1763
2221
  const own = targetQuestionFor(f);
1764
2222
  if (questionId({ step: TARGETS_STEP, repo, ...own }) === q.id)
1765
2223
  return true;
1766
- return targetGroupQuestion(repo, f) === q.question.trim() && q.evidence.includes(own.evidence[0]);
2224
+ return targetGroupWordings(repo, f, facts).includes(q.question.trim()) && q.evidence.includes(own.evidence[0]);
1767
2225
  });
1768
2226
  }
1769
2227
  function staleTargetQuestions(input) {
@@ -2055,7 +2513,9 @@ function catalogWithFacts(given) {
2055
2513
  const remap = /* @__PURE__ */ new Map();
2056
2514
  const stepTo = /* @__PURE__ */ new Map();
2057
2515
  let join10;
2516
+ let answerMisses;
2058
2517
  let estateJoin;
2518
+ let terms;
2059
2519
  let records0 = [...kept2, ...newRecords];
2060
2520
  if (input.estate) {
2061
2521
  const repos = joinReposOf(op, [{ repo, facts }, ...others], renames);
@@ -2069,6 +2529,16 @@ function catalogWithFacts(given) {
2069
2529
  });
2070
2530
  join10 = joinAbout(whole, repo);
2071
2531
  estateJoin = { whole, repos };
2532
+ const named2 = { ...input.estateTargets, [repo]: input.targets ?? {} };
2533
+ const mine2 = /* @__PURE__ */ new Set([
2534
+ factIdPart(repo),
2535
+ ...repos.filter((r) => r.repo === repo).flatMap((r) => [r.component, ...(r.modules ?? []).map((m) => m.component)]).filter((x) => !!x).map(factIdPart),
2536
+ ...facts.flatMap((f) => f.component ? [factIdPart(f.component)] : [])
2537
+ ]);
2538
+ answerMisses = whole.misses.filter((m) => {
2539
+ const t = named2[m.call.repo]?.[m.call.fact];
2540
+ return !!t && t !== NO_TARGET && (m.call.repo === repo || mine2.has(factIdPart(m.target)));
2541
+ });
2072
2542
  records0 = applyFactJoins(records0, join10, repos, {
2073
2543
  callers: joinCallers({
2074
2544
  repos,
@@ -2079,6 +2549,8 @@ function catalogWithFacts(given) {
2079
2549
  join: whole,
2080
2550
  only: [repo]
2081
2551
  });
2552
+ terms = joinTerms({ repos, join: whole, bundleFolders: joinConventions(op).bundleFolders });
2553
+ records0 = [...records0, ...termGrantRecords(terms, repos, { only: [repo] })];
2082
2554
  for (const j of join10.joins) {
2083
2555
  const id = j.call.repo === repo ? projected.ids[j.call.fact] : void 0;
2084
2556
  if (!id || remap.has(id))
@@ -2185,7 +2657,9 @@ function catalogWithFacts(given) {
2185
2657
  notes: merged.notes,
2186
2658
  ...join10 ? { join: join10 } : {},
2187
2659
  ...linkEvidence ? { linkEvidence } : {},
2188
- ...sharedWhole ? { shared: sharedJoinAbout(sharedWhole, repo) } : {}
2660
+ ...sharedWhole ? { shared: sharedJoinAbout(sharedWhole, repo) } : {},
2661
+ ...terms ? { terms } : {},
2662
+ ...answerMisses?.length ? { answerMisses } : {}
2189
2663
  };
2190
2664
  }
2191
2665
  function prototypeLeftOut(input) {
@@ -2238,6 +2712,61 @@ function estateFromFacts(input) {
2238
2712
  });
2239
2713
  return { records, specs, join: join10, invalid };
2240
2714
  }
2715
+ function answerRuleOffers(input) {
2716
+ const ruled = input.questions.filter((q) => q.askedBy?.step === TARGETS_STEP && q.state === "answered" && !!q.answer?.match);
2717
+ const groups = /* @__PURE__ */ new Map();
2718
+ for (const r of input.repos)
2719
+ for (const f of r.facts) {
2720
+ if (f.kind !== "call")
2721
+ continue;
2722
+ const q = answeredQuestionOfCall(r.repo, r.facts, input.questions, f.id);
2723
+ const label2 = q ? answerLabel2(q) : void 0;
2724
+ if (!q || !label2 || label2 === TARGETS_NONE || label2 === TARGETS_SPLIT || label2 === TARGETS_ANOTHER)
2725
+ continue;
2726
+ const url = urlOf(f, r.facts);
2727
+ const host = url ? urlHostPort(url)?.host : void 0;
2728
+ const via = host ? `on ${host.toLowerCase()}` : f.base ? `through ${f.base}` : void 0;
2729
+ if (!via)
2730
+ continue;
2731
+ groups.set(via, [
2732
+ ...groups.get(via) ?? [],
2733
+ { repo: r.repo, q, label: label2, f, facts: r.facts, ...r.type ? { type: r.type } : {} }
2734
+ ]);
2735
+ }
2736
+ const out = [];
2737
+ for (const [via, xs] of [...groups].sort(([a], [b]) => a.localeCompare(b))) {
2738
+ const repos = [...new Set(xs.map((x) => x.repo))].sort();
2739
+ const labels = new Set(xs.map((x) => slugify(x.label)));
2740
+ if (repos.length < 2 || labels.size !== 1)
2741
+ continue;
2742
+ if (xs.every((x) => ruled.some((q) => ruleCoversCall(q.answer.match, x.f, x.facts))))
2743
+ continue;
2744
+ const label2 = xs[0].label;
2745
+ const prefixes = new Set(xs.map((x) => targetPathPrefix(x.f.path)));
2746
+ const prefix = prefixes.size === 1 ? [...prefixes][0] : void 0;
2747
+ const match = via.startsWith("on ") ? via.slice(3) : prefix && prefix !== "/" ? `${prefix}/**` : void 0;
2748
+ const types = new Set(xs.map((x) => x.type));
2749
+ const type = types.size === 1 ? xs[0].type : void 0;
2750
+ const questions = [...new Set(xs.map((x) => x.q.id))].sort();
2751
+ const first = xs.find((x) => x.q.id === questions[0]).q;
2752
+ const n = first.options.findIndex((o) => o.label === label2);
2753
+ const pick = n >= 0 ? `--option ${n + 1}` : `--text "${label2}"`;
2754
+ if (!match || !type)
2755
+ continue;
2756
+ const command = `atticus questions answer ${first.id} ${pick} --match ${match} --scope repo-type --type ${type}`;
2757
+ out.push({
2758
+ via,
2759
+ label: label2,
2760
+ repos,
2761
+ questions,
2762
+ match,
2763
+ type,
2764
+ command,
2765
+ line: `${repos.length} repos (${repos.join(", ")}) answer the calls ${via} the same way, ${label2} (${questions.join(", ")}): one answer can say it for every ${type} repo. As a rule: ${command}.`
2766
+ });
2767
+ }
2768
+ return out;
2769
+ }
2241
2770
 
2242
2771
  // packages/scanner/dist/facts-scan.js
2243
2772
  async function factsForScan(root, op, repo, commit, readerRecords, at3 = {}) {
@@ -2422,8 +2951,8 @@ async function checkScanSettings(s, repo) {
2422
2951
  if (!(isConfigFile(file) && names)) {
2423
2952
  const dropped = code.filter((f) => re.test(f));
2424
2953
  const root = mainRoots.find((d) => {
2425
- const under = code.filter((f) => f.startsWith(`${d}/`));
2426
- return under.length && under.every((f) => re.test(f));
2954
+ const under2 = code.filter((f) => f.startsWith(`${d}/`));
2955
+ return under2.length && under2.every((f) => re.test(f));
2427
2956
  });
2428
2957
  const why = " so it is still read; only a build or config file that leaves it out itself can say so";
2429
2958
  if (dropped.length * 2 > code.length) {
@@ -3329,8 +3858,8 @@ async function resolveSettingsTemplate(t, repo, repoId) {
3329
3858
  out.exclude.push({ path: e.path, why: e.why, at: `${first}:1` });
3330
3859
  }
3331
3860
  for (const rule of t.settings.prefixes) {
3332
- const candidates = (await files.matching(rule.files)).sort((a, b) => a.length - b.length || a.localeCompare(b));
3333
- for (const f of candidates) {
3861
+ const candidates2 = (await files.matching(rule.files)).sort((a, b) => a.length - b.length || a.localeCompare(b));
3862
+ for (const f of candidates2) {
3334
3863
  const hit = await readRule(rule, f, files);
3335
3864
  if (!hit)
3336
3865
  continue;
@@ -4054,7 +4583,7 @@ function parseEntry(s) {
4054
4583
  const m = /^([A-Za-z]+)\s+(\S+)$/.exec(s.trim());
4055
4584
  return m ? { method: m[1].toUpperCase(), path: m[2] } : { path: s.trim() };
4056
4585
  }
4057
- var segs = (p) => normalizePath(p).toLowerCase().split("/").filter(Boolean);
4586
+ var segs2 = (p) => normalizePath(p).toLowerCase().split("/").filter(Boolean);
4058
4587
  var sameMethod = (a, b) => !a || !b || a.toUpperCase() === b.toUpperCase();
4059
4588
  async function joinEstate(o) {
4060
4589
  const byId = new Map(o.records.map((r) => [r.id, r]));
@@ -4066,8 +4595,8 @@ async function joinEstate(o) {
4066
4595
  const out = [i.normalizedPath];
4067
4596
  const route = i.route ? byId.get(i.route) : void 0;
4068
4597
  if (route?.kind === "GatewayRoute") {
4069
- const base2 = segs(route.basepath);
4070
- const p = segs(i.normalizedPath);
4598
+ const base2 = segs2(route.basepath);
4599
+ const p = segs2(i.normalizedPath);
4071
4600
  if (base2.length && base2.every((s, k) => p[k] === s))
4072
4601
  out.push(`/${p.slice(base2.length).join("/")}`);
4073
4602
  }
@@ -4182,27 +4711,27 @@ async function joinEstate(o) {
4182
4711
  within = "estate";
4183
4712
  hits = servingExactly(flow.component, want);
4184
4713
  }
4185
- const candidates = [...new Set(hits.map((e) => e.component))].sort();
4186
- if (candidates.length === 0) {
4714
+ const candidates2 = [...new Set(hits.map((e) => e.component))].sort();
4715
+ if (candidates2.length === 0) {
4187
4716
  miss({
4188
4717
  reason: "no-target",
4189
4718
  message: `${s.to.component} isn't a component in the catalog, and neither an Interface from ${flow.component} nor an entry point of the estate serves ${s.to.entry}`
4190
4719
  });
4191
4720
  continue;
4192
4721
  }
4193
- if (candidates.length > 1) {
4194
- const repos = [...new Set(candidates.map(repoOfComponent))];
4722
+ if (candidates2.length > 1) {
4723
+ const repos = [...new Set(candidates2.map(repoOfComponent))];
4195
4724
  const of = repos.length === 1 && repos[0] ? repos[0] : "the estate";
4196
4725
  miss({
4197
4726
  reason: "no-target",
4198
- message: `${s.to.component} isn't a component in the catalog, and ${candidates.length} components of ${of} serve ${s.to.entry} (${candidates.join(", ")}): a person says which`
4727
+ message: `${s.to.component} isn't a component in the catalog, and ${candidates2.length} components of ${of} serve ${s.to.entry} (${candidates2.join(", ")}): a person says which`
4199
4728
  });
4200
4729
  asks.push({
4201
4730
  from,
4202
4731
  caller: flow.component,
4203
4732
  named: s.to.component,
4204
4733
  what: s.to.entry,
4205
- candidates
4734
+ candidates: candidates2
4206
4735
  });
4207
4736
  continue;
4208
4737
  }
@@ -4430,6 +4959,17 @@ function fieldLineage(f, field) {
4430
4959
  }
4431
4960
 
4432
4961
  // packages/scanner/dist/hosts-asked.js
4962
+ var segs3 = (p) => p.split(/[?#]/)[0].split("/").filter(Boolean).map((x) => /^[{:<$]/.test(x) ? "{}" : x);
4963
+ var underPath = (path, base2) => {
4964
+ const b = segs3(base2);
4965
+ const c = segs3(path);
4966
+ return b.length > 0 && b.length <= c.length && b.every((x, i) => x === c[i]);
4967
+ };
4968
+ var servesPath = (entry, path) => {
4969
+ const e = segs3(entry);
4970
+ const c = segs3(path);
4971
+ return e.length === c.length && e.every((x, i) => x === "{}" || c[i] === "{}" || x === c[i]);
4972
+ };
4433
4973
  var HTTP_TYPES = /* @__PURE__ */ new Set(["rest", "graphql", "soap", "websocket", "sse", "webhook"]);
4434
4974
  var CONFIG_FILES = [
4435
4975
  "**/application*.properties",
@@ -4492,8 +5032,12 @@ async function unknownHosts(o) {
4492
5032
  const entry = byHost.get(h.label) ?? {
4493
5033
  ...h.port !== void 0 ? { port: h.port } : {},
4494
5034
  explicit: h.label !== h.host,
4495
- calls: []
5035
+ calls: [],
5036
+ paths: /* @__PURE__ */ new Set()
4496
5037
  };
5038
+ const path = /^[a-z][a-z0-9+.-]*:\/\/[^/?#]*(\/[^?#]*)?/i.exec(url)?.[1];
5039
+ if (path)
5040
+ entry.paths.add(path);
4497
5041
  const at3 = `${e.path}:${e.line}`;
4498
5042
  if (!entry.calls.some((c) => c.repo === repo && c.at === at3))
4499
5043
  entry.calls.push({ repo, at: at3 });
@@ -4546,6 +5090,25 @@ async function unknownHosts(o) {
4546
5090
  }
4547
5091
  const suggest = hits.length === 1 ? hits[0] : void 0;
4548
5092
  const calls = entry.calls.sort((a, b) => a.repo.localeCompare(b.repo) || a.at.localeCompare(b.at, "en", { numeric: true }));
5093
+ const byPath = [];
5094
+ for (const g of o.records) {
5095
+ if (g.kind !== "GatewayRoute")
5096
+ continue;
5097
+ const repo = g.evidence.find((e) => e.repo)?.repo;
5098
+ if (!repo || byPath.some((b) => b.repo === repo))
5099
+ continue;
5100
+ const under2 = [...entry.paths].filter((p) => underPath(p, g.basepath));
5101
+ if (!under2.length)
5102
+ continue;
5103
+ const comps = new Set([...compRepo].filter(([, r]) => r === repo).map(([c]) => c));
5104
+ const hit = o.records.find((r) => r.kind === "Endpoint" && comps.has(r.component) && under2.some((p) => servesPath(r.pathOrTopic, p)));
5105
+ byPath.push({
5106
+ repo,
5107
+ serves: hit ? [hit.method?.toUpperCase(), hit.pathOrTopic].filter(Boolean).join(" ") : `the routes under ${g.basepath}`
5108
+ });
5109
+ }
5110
+ byPath.sort((a, b) => a.repo.localeCompare(b.repo));
5111
+ const first = suggest ? [suggest.repo] : byPath.map((b) => b.repo).filter((x) => servers.includes(x));
4549
5112
  const about = Object.fromEntries(servers.flatMap((s) => {
4550
5113
  const d = o.repos.find((r) => r.id === s)?.description;
4551
5114
  return d ? [[s, { text: d.text, trust: d.trust }]] : [];
@@ -4553,9 +5116,10 @@ async function unknownHosts(o) {
4553
5116
  asks.push({
4554
5117
  host,
4555
5118
  calls,
4556
- servers: suggest ? [suggest.repo, ...servers.filter((s) => s !== suggest.repo)] : servers,
5119
+ servers: [...first, ...servers.filter((s) => !first.includes(s))],
4557
5120
  ...suggest ? { suggest } : {},
4558
- ...Object.keys(about).length ? { about } : {}
5121
+ ...Object.keys(about).length ? { about } : {},
5122
+ ...byPath.length ? { byPath } : {}
4559
5123
  });
4560
5124
  }
4561
5125
  return asks;
@@ -4566,18 +5130,24 @@ function aboutOf(a, repo) {
4566
5130
  return "";
4567
5131
  return d.trust === "suggested" ? `. What it is, as your assistant drafted it (unconfirmed): ${d.text}` : `. What it is: ${d.text}`;
4568
5132
  }
5133
+ function gatewayHostFix(host, byPath) {
5134
+ const repos = byPath.map((b) => b.repo);
5135
+ return `${repos.length === 1 ? `${repos[0]}'s routes serve` : `The routes of ${repos.join(", ")} serve`} the paths the calls to ${host} make, and no repo lists ${host}: it looks like a shared gateway's host. Once, not per call: list ${host} under hosts: on each proxy repo in repos.manifest.yaml (${repos.join(", ")}, and any other proxy on it); the path then picks the proxy, and this question retires itself`;
5136
+ }
4569
5137
  function hostQuestionDrafts(asks) {
4570
5138
  return asks.map((a) => {
4571
5139
  const repo = a.calls[0].repo;
5140
+ const byPath = new Map((a.byPath ?? []).map((b) => [b.repo, b.serves]));
4572
5141
  return {
4573
5142
  repo,
5143
+ ...a.byPath?.length ? { byPath: a.byPath } : {},
4574
5144
  draft: {
4575
5145
  question: hostQuestionText(a.host),
4576
5146
  options: [
4577
5147
  ...a.servers.map((s) => ({
4578
5148
  label: s,
4579
- means: (a.suggest?.repo === s ? `${s} serves HTTP, and its ${a.suggest.at} sets the port ${a.host.split(":").pop()} (${a.suggest.line})` : `${s} serves HTTP`) + aboutOf(a, s),
4580
- changes: `${a.host} goes under hosts for ${s} in repos.manifest.yaml, and the calls to it join ${s} on the next scan`
5149
+ means: (a.suggest?.repo === s ? `${s} serves HTTP, and its ${a.suggest.at} sets the port ${a.host.split(":").pop()} (${a.suggest.line})` : byPath.has(s) ? `${s} serves ${byPath.get(s)}, a path the calls to ${a.host} make` : `${s} serves HTTP`) + aboutOf(a, s),
5150
+ changes: byPath.has(s) ? `${a.host} goes under hosts for ${s} in repos.manifest.yaml, and the calls to it join ${s} on the next scan; on a shared gateway host, list it on each proxy repo instead (${[...byPath.keys()].join(", ")}, and any other proxy on it), and the path picks the proxy` : `${a.host} goes under hosts for ${s} in repos.manifest.yaml, and the calls to it join ${s} on the next scan`
4581
5151
  })),
4582
5152
  // O1: a system outside the estate, declared in the profile with the host as its alias.
4583
5153
  ...[
@@ -4696,12 +5266,12 @@ function parseLinkReference(source) {
4696
5266
  return { ok: true, reference: { ...estate ? { estate } : {}, repos } };
4697
5267
  }
4698
5268
  var stripped = (o) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== void 0));
4699
- function segs2(path) {
5269
+ function segs4(path) {
4700
5270
  return path.split(/[?#]/)[0].split("/").filter(Boolean).map((s) => /^(\{[^}]*\}|:\w+|\*)$/.test(s) ? "{}" : s.toLowerCase());
4701
5271
  }
4702
5272
  function pathMatch(a, b) {
4703
- const x = segs2(a);
4704
- const y = segs2(b);
5273
+ const x = segs4(a);
5274
+ const y = segs4(b);
4705
5275
  if (x.length === y.length && x.every((s, i) => s === y[i]))
4706
5276
  return 2;
4707
5277
  const [short, long] = x.length < y.length ? [x, y] : [y, x];
@@ -4996,19 +5566,33 @@ export {
4996
5566
  estateMergeInput,
4997
5567
  mergeEstate,
4998
5568
  curatedDirOf,
5569
+ TARGETS_MAX_SUGGESTED,
5570
+ TARGETS_ANOTHER,
5571
+ TARGETS_NO_EVIDENCE,
5572
+ nameWords,
5573
+ targetSuggestions,
5574
+ offeredSuggestions,
5575
+ targetPicker,
5576
+ pickerLines,
5577
+ topicQuestionDrafts,
4999
5578
  TARGETS_STEP,
5000
5579
  TARGETS_NONE,
5001
5580
  remapIds,
5002
5581
  targetQuestionFor,
5582
+ suggestionWhy,
5003
5583
  targetQuestionDrafts,
5004
5584
  TARGETS_SPLIT,
5005
5585
  targetPathPrefix,
5006
5586
  targetGroupQuestion,
5587
+ targetGroupWordings,
5007
5588
  splitTargetGroups,
5008
5589
  groupedTargetDrafts,
5590
+ targetRuleOffers,
5009
5591
  ruleCoversCall,
5010
5592
  ruledTargets,
5011
5593
  targetsFromAnswers,
5594
+ answeredQuestionOfCall,
5595
+ answerReconfirmed,
5012
5596
  staleTargetQuestions,
5013
5597
  componentRenames,
5014
5598
  factsRecords,
@@ -5020,6 +5604,7 @@ export {
5020
5604
  catalogWithFacts,
5021
5605
  prototypeLeftOut,
5022
5606
  estateFromFacts,
5607
+ answerRuleOffers,
5023
5608
  factsForScan,
5024
5609
  estateFacts,
5025
5610
  NO_SETTINGS,
@@ -5063,6 +5648,7 @@ export {
5063
5648
  fieldLineage,
5064
5649
  lineSetsPort,
5065
5650
  unknownHosts,
5651
+ gatewayHostFix,
5066
5652
  hostQuestionDrafts,
5067
5653
  parseLinkReference,
5068
5654
  measureLinks,