@maycombhq/atticus 2.0.0-beta.26 → 2.0.0-beta.27.1

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 (325) hide show
  1. package/dist/bin.js +3 -3
  2. package/dist/{chunk-7JZONWAA.js → chunk-23OQZY5Z.js} +22 -18
  3. package/dist/{chunk-UTZMF5CV.js → chunk-23TTURB2.js} +1 -1
  4. package/dist/{chunk-YIOYKA4V.js → chunk-2AIOOA3U.js} +7 -7
  5. package/dist/chunk-2ANBMA74.js +107 -0
  6. package/dist/{chunk-ZYLGEWTC.js → chunk-2FORECYK.js} +78 -57
  7. package/dist/{chunk-D5H3RZNE.js → chunk-2J2GMERV.js} +16 -15
  8. package/dist/{chunk-ZDA72732.js → chunk-2MRYL45Z.js} +50 -9
  9. package/dist/{chunk-RBO4A7TC.js → chunk-2WPUSHB6.js} +15 -15
  10. package/dist/{chunk-2IO6XH37.js → chunk-3BQDBTQJ.js} +15 -15
  11. package/dist/{chunk-B3JHERXM.js → chunk-3CMGSQIA.js} +7 -5
  12. package/dist/{chunk-UFIQ5FWY.js → chunk-3M3MDBOG.js} +1 -1
  13. package/dist/chunk-3NGHSBVS.js +50 -0
  14. package/dist/{chunk-DHQXCP2X.js → chunk-3PBIZBWN.js} +1 -1
  15. package/dist/{chunk-CFK6CFXM.js → chunk-3PG6QOQF.js} +9 -9
  16. package/dist/chunk-3PN7KJBA.js +48 -0
  17. package/dist/{chunk-DARX3ATP.js → chunk-3TWERSTY.js} +11 -11
  18. package/dist/chunk-3XNE6XXF.js +211 -0
  19. package/dist/chunk-3YL2GZZH.js +55 -0
  20. package/dist/{chunk-ZGULQAPZ.js → chunk-44SWXDD7.js} +8 -5
  21. package/dist/{chunk-XI3GPYP4.js → chunk-44XGOSUU.js} +5 -5
  22. package/dist/{chunk-SAPX3PVK.js → chunk-4BK5EJ2C.js} +11 -11
  23. package/dist/{chunk-OH2OHNB5.js → chunk-4FLIW5PJ.js} +4 -4
  24. package/dist/{chunk-EUTZTJIO.js → chunk-4HMOOBIR.js} +19 -15
  25. package/dist/chunk-4NPWOUI2.js +514 -0
  26. package/dist/{chunk-RQM5Y3HJ.js → chunk-4UVTNHA6.js} +1 -1
  27. package/dist/{chunk-KVVNAUIG.js → chunk-4XK3HLOH.js} +1 -0
  28. package/dist/{chunk-ZQGFZJH5.js → chunk-523NRKHF.js} +4 -4
  29. package/dist/chunk-5A4FHGTI.js +34 -0
  30. package/dist/{chunk-SDHGFMES.js → chunk-5CIW5RMP.js} +3 -3
  31. package/dist/{chunk-GJSLO2E2.js → chunk-5GCCG3GJ.js} +11 -5
  32. package/dist/{chunk-LCRQPWTC.js → chunk-5KR2DHDW.js} +19 -18
  33. package/dist/{chunk-UIYPX2BA.js → chunk-5PAIR73N.js} +27 -26
  34. package/dist/{chunk-K35VNKJH.js → chunk-5YEUAZZE.js} +8 -8
  35. package/dist/{chunk-DB6TDJ4T.js → chunk-5YX7MJWW.js} +22 -21
  36. package/dist/{chunk-IH6BYFMH.js → chunk-5ZFLP2IK.js} +6 -6
  37. package/dist/chunk-66CMRGI2.js +44 -0
  38. package/dist/{chunk-YWQZ7CCW.js → chunk-6DHGNY3O.js} +18 -17
  39. package/dist/{chunk-WLA2JZ2K.js → chunk-6ESJWPR3.js} +8 -8
  40. package/dist/{chunk-2SCZZQNQ.js → chunk-6GX3OFEZ.js} +121 -15
  41. package/dist/{chunk-2HDNOUJU.js → chunk-6H62UHY5.js} +7065 -3456
  42. package/dist/{chunk-YYV276DM.js → chunk-6MSACVCY.js} +22 -21
  43. package/dist/{chunk-GXJ2PSDW.js → chunk-6OTGCKYH.js} +9 -9
  44. package/dist/{chunk-HSJKYDHI.js → chunk-6TXB2WR6.js} +5 -5
  45. package/dist/{chunk-KL7UHAOR.js → chunk-6VFR3DYS.js} +36 -21
  46. package/dist/{chunk-KS2IQYTZ.js → chunk-7BOGXFZ3.js} +11 -11
  47. package/dist/chunk-7GZ46N4V.js +37 -0
  48. package/dist/{chunk-KFJMQUSK.js → chunk-7HUCEHUK.js} +16 -15
  49. package/dist/{chunk-LY7DOYX2.js → chunk-7LOXUBRB.js} +53 -112
  50. package/dist/{chunk-NQDVD2YR.js → chunk-7SO6CGJH.js} +12 -12
  51. package/dist/{chunk-LZFKJ2BR.js → chunk-A3LVMCA5.js} +1 -1
  52. package/dist/{chunk-2XIIUXGX.js → chunk-A3QZZEJA.js} +16 -16
  53. package/dist/{chunk-PXDAGXQN.js → chunk-AHAEHBH5.js} +11 -11
  54. package/dist/{chunk-PFWP624T.js → chunk-AKZTCZ6F.js} +4 -4
  55. package/dist/{chunk-V5ZKGBYL.js → chunk-AOQG37K4.js} +8 -6
  56. package/dist/chunk-APYIIVBH.js +72 -0
  57. package/dist/{chunk-HV6PXXK7.js → chunk-AQLDQK2M.js} +3 -3
  58. package/dist/{chunk-YJBD5NDV.js → chunk-AXJCABA5.js} +6 -6
  59. package/dist/{chunk-CG6MG7SE.js → chunk-AZBP5DTU.js} +14 -14
  60. package/dist/chunk-B4WPO6FX.js +58 -0
  61. package/dist/{chunk-3GEAUW62.js → chunk-BSGOUHL6.js} +16 -15
  62. package/dist/{chunk-D4TW3PUO.js → chunk-BUBKKEUV.js} +5 -5
  63. package/dist/chunk-BV7WB32T.js +1068 -0
  64. package/dist/{chunk-I72PEROE.js → chunk-C5DY4R7R.js} +6 -6
  65. package/dist/chunk-CBFQO2F2.js +62 -0
  66. package/dist/{chunk-723OQZ3N.js → chunk-CHS5BJ34.js} +6 -6
  67. package/dist/{chunk-2FTHLB2H.js → chunk-CLM5Z3R5.js} +5 -5
  68. package/dist/{chunk-7AEB74KW.js → chunk-CPB4XMFI.js} +9 -9
  69. package/dist/{chunk-KZH5YV6J.js → chunk-CWJDZ5VP.js} +6 -6
  70. package/dist/chunk-CWKQRP6Y.js +56 -0
  71. package/dist/{chunk-PLSCWC2V.js → chunk-D3L5SO27.js} +5 -5
  72. package/dist/{chunk-OI32KTDM.js → chunk-D566V3T3.js} +13 -13
  73. package/dist/{chunk-JLTJAOO4.js → chunk-DDRTAEFZ.js} +50 -13
  74. package/dist/{chunk-TYN5SG5H.js → chunk-DGNTEKF6.js} +403 -148
  75. package/dist/{chunk-VUSYN4R4.js → chunk-DNDIT3LD.js} +8 -8
  76. package/dist/{chunk-IERXBWQU.js → chunk-DNKYWTVZ.js} +20 -19
  77. package/dist/{chunk-KJD4DLRZ.js → chunk-DS2OZXBN.js} +22 -21
  78. package/dist/{chunk-CSHJZFOE.js → chunk-DTW37FJ6.js} +91 -93
  79. package/dist/{chunk-KAWWXCPI.js → chunk-DVQCYF3V.js} +3 -3
  80. package/dist/{chunk-UZBLVNW6.js → chunk-DX7WEXYG.js} +38 -17
  81. package/dist/{chunk-PZFZPHCT.js → chunk-E7Q52EOO.js} +11 -11
  82. package/dist/{chunk-R2FUFBHW.js → chunk-EFDUC35B.js} +3 -3
  83. package/dist/chunk-EHT2KP5A.js +43 -0
  84. package/dist/{chunk-43OWNS5N.js → chunk-EHXEJFHD.js} +5 -5
  85. package/dist/{chunk-HQMLY2R6.js → chunk-ELJ5Q4J2.js} +2 -2
  86. package/dist/{chunk-BD7HBZLP.js → chunk-ELZGWEK4.js} +6 -6
  87. package/dist/{chunk-F4EGHECF.js → chunk-EM6DKBTJ.js} +3 -3
  88. package/dist/{chunk-PBDIVTFL.js → chunk-FADIWOA5.js} +3 -3
  89. package/dist/{chunk-IL7PVMUO.js → chunk-FBG3QHOL.js} +6 -6
  90. package/dist/{chunk-LHN5UCXD.js → chunk-FBNJZ3VH.js} +3 -3
  91. package/dist/chunk-FFIHRQ3O.js +67 -0
  92. package/dist/chunk-FT55WYNB.js +39 -0
  93. package/dist/{chunk-E5NHFHGC.js → chunk-FVT6LUOC.js} +7 -7
  94. package/dist/{chunk-KUEG2Y7M.js → chunk-FYRBBFIF.js} +8 -8
  95. package/dist/chunk-FZ2K3IXP.js +46 -0
  96. package/dist/{chunk-IBIIKUC7.js → chunk-G33UIUG3.js} +46 -20
  97. package/dist/chunk-G4TFQ4EG.js +60 -0
  98. package/dist/{chunk-2GT47PWU.js → chunk-GBJRFFDW.js} +5 -5
  99. package/dist/{chunk-BIKMME4S.js → chunk-GEHB2LMA.js} +28 -27
  100. package/dist/{chunk-NMURRF5F.js → chunk-GF6GBHFN.js} +13 -11
  101. package/dist/{chunk-6SIGGA37.js → chunk-GLNSLQSV.js} +26 -25
  102. package/dist/{chunk-BABRMZET.js → chunk-GZILYRGC.js} +3 -3
  103. package/dist/{chunk-5JGRF53S.js → chunk-GZSOZYEP.js} +3 -3
  104. package/dist/{chunk-Z33UNTHI.js → chunk-HBHPOKL2.js} +7 -7
  105. package/dist/{chunk-2JT4QV3Q.js → chunk-HDWVR5KD.js} +4 -4
  106. package/dist/{chunk-UJ5ZJS4B.js → chunk-HNU4AQXB.js} +22 -21
  107. package/dist/{chunk-IJN5PSDU.js → chunk-HOEZQRZU.js} +57 -27
  108. package/dist/{chunk-HWPX3T55.js → chunk-HPCGQAYH.js} +31 -24
  109. package/dist/{chunk-JJEXMHNZ.js → chunk-HUMM4S5I.js} +6 -6
  110. package/dist/{chunk-BIWNRS5I.js → chunk-I2NGDERG.js} +78 -47
  111. package/dist/{chunk-IGOE6KPG.js → chunk-I34CXV2C.js} +185 -11
  112. package/dist/{chunk-DOU52XFZ.js → chunk-I4P72R2F.js} +61 -28
  113. package/dist/{chunk-6U65YB54.js → chunk-I57IH5X6.js} +360 -271
  114. package/dist/{chunk-WYO4L4NU.js → chunk-I5X4WU7U.js} +6 -6
  115. package/dist/{chunk-DXLWZ3BJ.js → chunk-IDFUGYTS.js} +8 -8
  116. package/dist/{chunk-5A4RHEEL.js → chunk-INCFIDCB.js} +2 -2
  117. package/dist/{chunk-RTCZKKG7.js → chunk-IPMPLTEG.js} +3 -3
  118. package/dist/{chunk-QAFQLILX.js → chunk-IPSZDVLI.js} +12 -12
  119. package/dist/{chunk-ZFLBWL2G.js → chunk-J3ZUKQLV.js} +11 -3
  120. package/dist/chunk-J4L64TUA.js +58 -0
  121. package/dist/chunk-JA7AUBHU.js +51 -0
  122. package/dist/chunk-JD3QDLM2.js +50 -0
  123. package/dist/{chunk-4DHYXODN.js → chunk-JF2HM2IF.js} +4 -4
  124. package/dist/{chunk-XEWFVHOT.js → chunk-JGR4X2UA.js} +24 -23
  125. package/dist/chunk-JOG5O2ZH.js +185 -0
  126. package/dist/{chunk-ACY3U2RD.js → chunk-JRXFZB6J.js} +8 -8
  127. package/dist/{chunk-ZWMHL346.js → chunk-JWIAVNEC.js} +20 -19
  128. package/dist/{chunk-MQ6HP2TU.js → chunk-KMBI6IQD.js} +6 -6
  129. package/dist/chunk-KOITA526.js +42 -0
  130. package/dist/chunk-KZ5G3KEN.js +90 -0
  131. package/dist/{chunk-DPH4BS3F.js → chunk-L3KSU4QU.js} +17 -17
  132. package/dist/{chunk-4NWE2KY3.js → chunk-L4WFMAHI.js} +15 -14
  133. package/dist/{chunk-H7CSCA73.js → chunk-LAPVW2F6.js} +5 -5
  134. package/dist/{chunk-SZDOBIWE.js → chunk-LCQIRCOT.js} +55 -10
  135. package/dist/{chunk-ZLBUFK7L.js → chunk-LCWC6NDE.js} +7 -7
  136. package/dist/{chunk-ELR7DEQM.js → chunk-LH52QGNY.js} +34 -9
  137. package/dist/{chunk-WT6EXYEY.js → chunk-LJEEVZIH.js} +138 -22
  138. package/dist/{chunk-EVKDWJ5Y.js → chunk-LKLB5IJ7.js} +5 -5
  139. package/dist/{chunk-VIQHZA53.js → chunk-LP6BFBE5.js} +6 -6
  140. package/dist/{chunk-FIZ5LYL2.js → chunk-LQEMCF43.js} +16 -15
  141. package/dist/{chunk-RO6BE7ZS.js → chunk-LTVOQJKT.js} +7 -7
  142. package/dist/{chunk-C3TBDX7Y.js → chunk-M25UUEKC.js} +26 -25
  143. package/dist/{chunk-PXMV2LLY.js → chunk-M65AZ4ZE.js} +3 -5
  144. package/dist/chunk-MA44TMTL.js +190 -0
  145. package/dist/{chunk-EQMNMG6X.js → chunk-MA73J3E6.js} +13 -13
  146. package/dist/{chunk-P6EJNPFF.js → chunk-MBIJNU3D.js} +951 -409
  147. package/dist/chunk-MIKRDA2P.js +68 -0
  148. package/dist/{chunk-DJBXXYYA.js → chunk-MNOZDE6W.js} +15 -15
  149. package/dist/{chunk-QQAWI5LD.js → chunk-MP7W6OKP.js} +16 -15
  150. package/dist/chunk-MSNEGKI3.js +492 -0
  151. package/dist/{chunk-ZNYSBQIA.js → chunk-MUXYUIBV.js} +6 -6
  152. package/dist/{chunk-VJO7M34N.js → chunk-MZDHFWTN.js} +2 -2
  153. package/dist/{chunk-K3QKOVZN.js → chunk-N5DLB74D.js} +367 -71
  154. package/dist/{chunk-3D74UADA.js → chunk-NGSGJLKW.js} +2 -2
  155. package/dist/{chunk-3KP7OOJ4.js → chunk-NJ5IEZIG.js} +8 -8
  156. package/dist/chunk-NK6JCNJX.js +41 -0
  157. package/dist/{chunk-IYEET4VM.js → chunk-NNRQZUVW.js} +27 -26
  158. package/dist/{chunk-76AHTJVY.js → chunk-NNURP7VO.js} +15 -15
  159. package/dist/{chunk-GFFTVQ7R.js → chunk-NV5S63YK.js} +7 -7
  160. package/dist/{chunk-MKUBDKE2.js → chunk-NWAMUD7B.js} +29 -28
  161. package/dist/{chunk-CTJHEG6A.js → chunk-NWMFVPEP.js} +2 -0
  162. package/dist/{chunk-6EMJ4XFC.js → chunk-NWQ76YQ5.js} +31 -20
  163. package/dist/{chunk-H5BIVULF.js → chunk-O5BUMSB3.js} +10 -10
  164. package/dist/{chunk-IEIHVMM6.js → chunk-O6UC7ASJ.js} +5 -5
  165. package/dist/{chunk-Q3RKXK5Z.js → chunk-OBQL7GX4.js} +28 -27
  166. package/dist/{chunk-NCZS2BN2.js → chunk-OILAH2C7.js} +21 -20
  167. package/dist/{chunk-U3JXMY56.js → chunk-OOZKLLW7.js} +28 -25
  168. package/dist/{chunk-UAYU6K24.js → chunk-ORGB6645.js} +16 -15
  169. package/dist/{chunk-BGOAJFPB.js → chunk-OUALZ5RA.js} +1 -1
  170. package/dist/{chunk-6TZ4YRGJ.js → chunk-OUDGBJC2.js} +16 -9
  171. package/dist/{chunk-W4SMKUAK.js → chunk-OUGTAOGA.js} +2 -2
  172. package/dist/{chunk-7ZBYRMWK.js → chunk-OY2VC2IU.js} +26 -25
  173. package/dist/{chunk-GHST3KAB.js → chunk-OY6H7JX6.js} +5 -5
  174. package/dist/{chunk-KZ4I5M2X.js → chunk-P7H5WZH6.js} +37 -19
  175. package/dist/{chunk-ZA2PWNR3.js → chunk-PCIENCB7.js} +16 -15
  176. package/dist/{chunk-DXBXZNKV.js → chunk-PGAXZLNF.js} +21 -13
  177. package/dist/{chunk-UXVKFOMC.js → chunk-PPKH6ULR.js} +152 -20
  178. package/dist/{chunk-IP6ARMZU.js → chunk-PT77IUYQ.js} +58 -36
  179. package/dist/chunk-PVJZR4JB.js +653 -0
  180. package/dist/chunk-Q7EUPQEG.js +5 -0
  181. package/dist/{chunk-HNNMT5L2.js → chunk-Q7YDUGVZ.js} +1 -1
  182. package/dist/{chunk-MTIRNHRJ.js → chunk-QK3UFHFC.js} +1 -1
  183. package/dist/{chunk-VCXFMXMX.js → chunk-QLT3WYTD.js} +6 -6
  184. package/dist/{chunk-UWBPC5XH.js → chunk-QNXMVJMA.js} +8 -8
  185. package/dist/{chunk-XDLMQL5A.js → chunk-QPAANKUR.js} +7 -7
  186. package/dist/chunk-QQUAEM3U.js +57 -0
  187. package/dist/chunk-QU3ENIJV.js +52 -0
  188. package/dist/{chunk-TPKJD42W.js → chunk-QUFZDWPC.js} +8 -8
  189. package/dist/{chunk-DB3NWAU3.js → chunk-QXSYFB5L.js} +4 -4
  190. package/dist/{chunk-QXCGRQGO.js → chunk-QXXEOH3A.js} +18 -6
  191. package/dist/{chunk-QA4O2GGC.js → chunk-R4TUWD4C.js} +17 -1
  192. package/dist/{chunk-CNEOKSTO.js → chunk-R6KZWNZM.js} +34 -31
  193. package/dist/{chunk-CNT6T2JM.js → chunk-R7NPDUBL.js} +16 -15
  194. package/dist/{chunk-HVWPN2RY.js → chunk-R7VX5BSP.js} +16 -15
  195. package/dist/chunk-RCPWEZD7.js +47 -0
  196. package/dist/{chunk-FOOU5OJE.js → chunk-RDFRB26Z.js} +3 -3
  197. package/dist/{chunk-ISCX25D7.js → chunk-RTHQIGGY.js} +200 -56
  198. package/dist/{chunk-FYCN2Y5P.js → chunk-RX2SMQV3.js} +19 -18
  199. package/dist/{chunk-XIGVTH24.js → chunk-RZEYZOLW.js} +19 -19
  200. package/dist/{chunk-VTR4AC2U.js → chunk-RZYRUXSU.js} +4 -4
  201. package/dist/{chunk-YLXPJWNO.js → chunk-S5O57P5P.js} +17 -16
  202. package/dist/{chunk-CWLXVRFH.js → chunk-S6TLXRBR.js} +7 -7
  203. package/dist/{chunk-MCORC2LG.js → chunk-SF3HXNXR.js} +6 -6
  204. package/dist/{chunk-BSZII65X.js → chunk-SFCFL7Y5.js} +1 -1
  205. package/dist/chunk-SJ2Z3AWF.js +89 -0
  206. package/dist/{chunk-KFZ5IXEZ.js → chunk-SKVLJL2E.js} +28 -27
  207. package/dist/chunk-SMFFUFMN.js +1876 -0
  208. package/dist/{chunk-IDRCBMJF.js → chunk-SP5BWA5H.js} +32 -31
  209. package/dist/chunk-SRIU7L4Z.js +425 -0
  210. package/dist/{chunk-CUTMM4NY.js → chunk-SSYD4XIW.js} +154 -25
  211. package/dist/{chunk-UBEFT3MQ.js → chunk-TFN2N227.js} +6 -6
  212. package/dist/{chunk-YEHSJY6B.js → chunk-TLSL7OII.js} +13 -13
  213. package/dist/{chunk-B7KGNEFI.js → chunk-TM2WY65Q.js} +25 -24
  214. package/dist/{chunk-6P67IUET.js → chunk-TMETWJFO.js} +11 -11
  215. package/dist/{chunk-SRB54QGX.js → chunk-TMMGQBLO.js} +20 -19
  216. package/dist/{chunk-VGGSHDQU.js → chunk-TOSHT6NJ.js} +8 -8
  217. package/dist/{chunk-64LSDT3D.js → chunk-TPKDYSHO.js} +12 -12
  218. package/dist/{chunk-OXCHO2QS.js → chunk-TQISA4VW.js} +26 -23
  219. package/dist/{chunk-NVVEVP5O.js → chunk-TRSNIJNM.js} +7 -7
  220. package/dist/{chunk-TQG2DDWH.js → chunk-TUMHMISE.js} +22 -21
  221. package/dist/{chunk-WM4EMP7T.js → chunk-U36V664P.js} +283 -61
  222. package/dist/{chunk-5UIGGXA5.js → chunk-U4K34CXK.js} +21 -20
  223. package/dist/{chunk-3KIMLBGZ.js → chunk-UDM6HGF4.js} +6 -6
  224. package/dist/{chunk-NMCPIYTF.js → chunk-UDM7LXNJ.js} +7 -7
  225. package/dist/{chunk-ZFEOIYK5.js → chunk-UEUPEUZX.js} +3 -3
  226. package/dist/{chunk-RCLBIJRN.js → chunk-UGJSKAZ2.js} +6 -6
  227. package/dist/{chunk-DS5M2J2H.js → chunk-UMIZYX3U.js} +16 -15
  228. package/dist/{chunk-63572EFC.js → chunk-USYDJY63.js} +21 -19
  229. package/dist/{chunk-V5FT3MZG.js → chunk-UXETN43F.js} +8 -8
  230. package/dist/{chunk-LBBI5P5G.js → chunk-V6BP4XHZ.js} +25 -24
  231. package/dist/chunk-V7DGFWDB.js +55 -0
  232. package/dist/chunk-VGXE7XFO.js +35 -0
  233. package/dist/{chunk-IZIGZ7KY.js → chunk-VSED7FYC.js} +13 -8
  234. package/dist/{chunk-HVOE7ZW2.js → chunk-VTQ55N4O.js} +19 -18
  235. package/dist/{chunk-P6DM2EFI.js → chunk-VVLWEM2Y.js} +6 -6
  236. package/dist/{chunk-YXKCE5BA.js → chunk-VWCNMDMZ.js} +5 -5
  237. package/dist/{chunk-EY3OVHNC.js → chunk-VX5CORDG.js} +24 -23
  238. package/dist/{chunk-XT3ZW7C7.js → chunk-W4SWXJZQ.js} +19 -18
  239. package/dist/{chunk-BV2BZIUF.js → chunk-W5UMEIYG.js} +25 -24
  240. package/dist/{chunk-VPQUFIE7.js → chunk-W6OY2PMB.js} +10 -10
  241. package/dist/chunk-W7NNZFIL.js +52 -0
  242. package/dist/{chunk-6ZDAEUKB.js → chunk-WJWSB65O.js} +1602 -452
  243. package/dist/{chunk-IFQJ3YQE.js → chunk-WNPGLGCJ.js} +5 -5
  244. package/dist/{chunk-MM7JSMLW.js → chunk-WNRIL6JQ.js} +18 -17
  245. package/dist/{chunk-TLBPTUFU.js → chunk-WPZCSFND.js} +20 -19
  246. package/dist/chunk-WTGQJXRJ.js +55 -0
  247. package/dist/{chunk-BEEHCL5O.js → chunk-WTLFRINF.js} +37 -36
  248. package/dist/{chunk-XIJBQM45.js → chunk-X5B7KYPD.js} +507 -20
  249. package/dist/{chunk-GNFZ227W.js → chunk-XIIT4PVT.js} +3 -3
  250. package/dist/{chunk-EECFUQP3.js → chunk-XKWPEY4B.js} +184 -46
  251. package/dist/{chunk-GAJBMPWC.js → chunk-XRNMQZFC.js} +28 -9
  252. package/dist/{chunk-BIAQ6NQS.js → chunk-XRTECHVH.js} +7 -7
  253. package/dist/{chunk-I2EWY3MG.js → chunk-XZY4GTCX.js} +14 -9
  254. package/dist/{chunk-V3M4VFUB.js → chunk-Y6S7VCYN.js} +6 -6
  255. package/dist/{chunk-MY3LDBMR.js → chunk-YAPVAYZN.js} +3 -3
  256. package/dist/{chunk-WH3ZFLXT.js → chunk-YBAJ5SAR.js} +197 -124
  257. package/dist/{chunk-ET7SPOBA.js → chunk-YHS7TSQS.js} +8 -8
  258. package/dist/{chunk-RK5P2DWD.js → chunk-YIGSUTW2.js} +1329 -92
  259. package/dist/{chunk-ANFBBJEV.js → chunk-YPXBGNUV.js} +24 -22
  260. package/dist/{chunk-MZXDSAKW.js → chunk-YRHKEXTP.js} +11 -11
  261. package/dist/{chunk-CPE7HLIK.js → chunk-YTPND655.js} +18 -17
  262. package/dist/{chunk-LTOBNBJ6.js → chunk-YZUOOTC3.js} +27 -26
  263. package/dist/{chunk-F6GRBF5L.js → chunk-Z245SJ64.js} +25 -24
  264. package/dist/{chunk-NP3PG6OI.js → chunk-Z5CIRZNO.js} +157 -89
  265. package/dist/chunk-ZCARJ77R.js +56 -0
  266. package/dist/{chunk-DASVVML7.js → chunk-ZIAMPN7N.js} +6 -6
  267. package/dist/chunk-ZNZYMUBK.js +53 -0
  268. package/dist/{chunk-NECDBPFP.js → chunk-ZOAX7W5S.js} +11 -11
  269. package/dist/{chunk-7IWMRZRI.js → chunk-ZQZRNVNS.js} +83 -40
  270. package/dist/{chunk-PGDVJWCI.js → chunk-ZT6GPGZ4.js} +52 -37
  271. package/dist/{chunk-H26T2LQL.js → chunk-ZW3OEHLT.js} +29 -28
  272. package/dist/files.json +653 -549
  273. package/dist/fixtures/forge/expected/crosscheck.json +726 -0
  274. package/dist/fixtures/forge/slots/README.md +13 -0
  275. package/dist/fixtures/forge/slots/build.json +2686 -0
  276. package/dist/fixtures/forge/slots/crosscheck/forge-ledger.crosscheck.yaml +8 -0
  277. package/dist/fixtures/forge/slots/facts/forge-ledger.jsonl +17 -0
  278. package/dist/fixtures/forge/slots/facts/forge-ledger.meta.json +9 -0
  279. package/dist/fixtures/forge/slots/legacy/joins.json +113 -0
  280. package/dist/fixtures/forge/slots/readers/forge-events.json +306 -0
  281. package/dist/fixtures/forge/slots/readers/forge-gateway.json +238 -0
  282. package/dist/fixtures/forge/slots/readers/forge-infra.json +264 -0
  283. package/dist/fixtures/forge/slots/readers/forge-ledger.json +756 -0
  284. package/dist/fixtures/forge/slots/readers/forge-portal-bff.json +349 -0
  285. package/dist/fixtures/forge/slots/readers/forge-portal-ui.json +214 -0
  286. package/dist/fixtures/forge/slots/readers/forge-reports-job.json +258 -0
  287. package/dist/packages/sdk/npm/index.js +3788 -2939
  288. package/dist/packages/ui/dist/assets/{elk-api-BdXSPeBO.js → elk-api-CPE6PVL8.js} +2 -2
  289. package/dist/packages/ui/dist/assets/index-BYcVqj0l.js +65 -0
  290. package/dist/packages/ui/dist/assets/index-DF52Ejvz.css +1 -0
  291. package/dist/packages/ui/dist/index.html +2 -2
  292. package/package.json +5 -5
  293. package/dist/chunk-24OXGB3P.js +0 -82
  294. package/dist/chunk-3FFIDQQB.js +0 -42
  295. package/dist/chunk-4N5W7LYW.js +0 -41
  296. package/dist/chunk-7NVLGPER.js +0 -45
  297. package/dist/chunk-A6LGX56J.js +0 -52
  298. package/dist/chunk-AHACUPGL.js +0 -46
  299. package/dist/chunk-DG7KYZAL.js +0 -40
  300. package/dist/chunk-DWD6BKHG.js +0 -52
  301. package/dist/chunk-EEVSFGIU.js +0 -50
  302. package/dist/chunk-EN3N6LNU.js +0 -52
  303. package/dist/chunk-FWQDH5NK.js +0 -55
  304. package/dist/chunk-GHCFWIUW.js +0 -38
  305. package/dist/chunk-GSIJWDXH.js +0 -43
  306. package/dist/chunk-HCC5547C.js +0 -232
  307. package/dist/chunk-HLDUWEO7.js +0 -36
  308. package/dist/chunk-K2NQTROJ.js +0 -170
  309. package/dist/chunk-LH4WAJLC.js +0 -45
  310. package/dist/chunk-M5IQUWJR.js +0 -59
  311. package/dist/chunk-MEMEO7YO.js +0 -988
  312. package/dist/chunk-MGNO4Q6V.js +0 -51
  313. package/dist/chunk-MZ6GOFRF.js +0 -55
  314. package/dist/chunk-N2AW2DHF.js +0 -51
  315. package/dist/chunk-N35Y5HZO.js +0 -47
  316. package/dist/chunk-NHFMLMLN.js +0 -257
  317. package/dist/chunk-PR6Z5L7W.js +0 -67
  318. package/dist/chunk-STBJ6SVJ.js +0 -50
  319. package/dist/chunk-U3RGBYXE.js +0 -62
  320. package/dist/chunk-URZKIL37.js +0 -42
  321. package/dist/chunk-W7HNZDHB.js +0 -71
  322. package/dist/chunk-YYZWSVIS.js +0 -33
  323. package/dist/chunk-ZAMSF2DF.js +0 -54
  324. package/dist/packages/ui/dist/assets/index-DRSUhpFi.css +0 -1
  325. package/dist/packages/ui/dist/assets/index-RZe5iotJ.js +0 -63
@@ -6,10 +6,12 @@ var __atticusPath = (p) => __atticusFileURLToPath(__atticusUrl(p));
6
6
  import {
7
7
  FileChangedError,
8
8
  ensureLocalIgnore,
9
+ hasSecretShape,
10
+ redactSecrets,
9
11
  withSharedFileLock,
10
12
  writeFileAtomic,
11
13
  writeFileIfUnchanged
12
- } from "./chunk-MEMEO7YO.js";
14
+ } from "./chunk-SMFFUFMN.js";
13
15
  import {
14
16
  AI_RUNTIMES,
15
17
  ASSISTANTS,
@@ -118,11 +120,11 @@ import {
118
120
  normalizePath,
119
121
  slugify,
120
122
  urlHostPort
121
- } from "./chunk-LZFKJ2BR.js";
123
+ } from "./chunk-A3LVMCA5.js";
122
124
  import {
123
125
  SCHEMA_VERSION,
124
126
  keptParse
125
- } from "./chunk-CTJHEG6A.js";
127
+ } from "./chunk-NWMFVPEP.js";
126
128
  import {
127
129
  require_dist
128
130
  } from "./chunk-BQGDB6ZL.js";
@@ -131,199 +133,6 @@ import {
131
133
  __toESM
132
134
  } from "./chunk-TV45EUGM.js";
133
135
 
134
- // packages/core/dist/cite.js
135
- var escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
136
- var PARAM = /^(\{[^}]*\}|:[^/]+|<[^>]+>|\$\{[^}]*\})$/;
137
- var PARAM_RE = "(?:\\{[^}]*\\}|:[A-Za-z_]\\w*|<[^>]+>|\\$\\{[^}]*\\})";
138
- var fieldKey = (f) => f.split(".").pop().toLowerCase().replace(/[^a-z0-9]/g, "");
139
- function lineNamesRoute(line, path) {
140
- const segs2 = path.split(/[?#]/, 1)[0].split("/").filter(Boolean);
141
- if (!segs2.some((s) => !PARAM.test(s))) {
142
- const body = segs2.map((s) => PARAM.test(s) ? PARAM_RE : escape(s)).join("/");
143
- if (new RegExp(`["'\`]/${body}/?["'\`]`).test(line))
144
- return true;
145
- if (!segs2.length && /\bpath:\s*(['"`])\1|\bindex:\s*true\b/.test(line))
146
- return true;
147
- const head = segs2.slice(0, -1).map(() => PARAM_RE).join("/");
148
- return segs2.length > 0 && new RegExp(`["'\`]/${head ? `${head}/` : ""}["'\`]\\s*\\+`).test(line);
149
- }
150
- for (let k = 0; k < segs2.length; k++) {
151
- const tail = segs2.slice(k);
152
- if (!tail.some((s) => !PARAM.test(s)))
153
- break;
154
- const re = new RegExp(`(?:/|["'\`])${tail.map((s) => PARAM.test(s) ? PARAM_RE : escape(s)).join("/")}(?![A-Za-z0-9_-])`, "i");
155
- if (re.test(line))
156
- return true;
157
- const last = tail[tail.length - 1];
158
- if (PARAM.test(last) && tail.length > 1) {
159
- const head = tail.slice(0, -1);
160
- const re2 = new RegExp(`/${head.map((s) => PARAM.test(s) ? PARAM_RE : escape(s)).join("/")}/?["'\`]`, "i");
161
- if (re2.test(line))
162
- return true;
163
- }
164
- }
165
- return false;
166
- }
167
- var lineNamesWord = (line, word) => {
168
- const w = word.trim();
169
- if (!w)
170
- return false;
171
- const before = /^[A-Za-z0-9_]/.test(w) ? "(^|[^A-Za-z0-9_])" : "";
172
- const after = /[A-Za-z0-9_]$/.test(w) ? "($|[^A-Za-z0-9_])" : "";
173
- return new RegExp(`${before}${escape(w)}${after}`, "i").test(line);
174
- };
175
- var lineNamesField = (line, field) => {
176
- const k = fieldKey(field);
177
- return k.length > 0 && line.toLowerCase().replace(/[^a-z0-9]/g, " ").replace(/ /g, "").includes(k);
178
- };
179
- var lineNamesClaim = (line, c) => c.kind === "route" ? lineNamesRoute(line, c.value) : c.kind === "word" ? lineNamesWord(line, c.value) : lineNamesField(line, c.value);
180
- function claimOnLines(lines, line, claim, window = 1) {
181
- const from = Math.max(1, line - window);
182
- const to = Math.min(lines.length, line + window);
183
- for (let i = from; i <= to; i++)
184
- if (lineNamesClaim(lines[i - 1] ?? "", claim))
185
- return true;
186
- return false;
187
- }
188
- function normalizeQuote(q2) {
189
- return q2.replace(/\r\n?/g, "\n").replace(/[‘’‚]/g, "'").replace(/[“”„]/g, '"').replace(/\s+/g, " ").trim().replace(/[;,.]+$/, "").trim();
190
- }
191
- function quoteMatches(line, quote) {
192
- if (!quote)
193
- return true;
194
- const q2 = normalizeQuote(quote).replace(/"/g, "'");
195
- if (q2 === "")
196
- return true;
197
- const l = normalizeQuote(line).replace(/"/g, "'");
198
- const at3 = q2.indexOf("<redacted>");
199
- if (at3 >= 0)
200
- return at3 === 0 || l.includes(q2.slice(0, at3).trimEnd());
201
- return l === q2 || l.startsWith(q2) || l.includes(q2);
202
- }
203
- var BINARY = /\.(png|jpe?g|gif|webp|ico|pdf|zip|jar|war|ear|gz|tgz|7z|exe|dll|so|dylib|class|wasm|woff2?|ttf|otf|mp[34]|mov|avi|bin|dat)$/i;
204
- var NOTEBOOK = /\.ipynb$/i;
205
- var MINIFIED = /(\.min\.(js|css)|[-.]bundle\.js|\.map)$/i;
206
- function isBinaryPath(path) {
207
- return BINARY.test(path);
208
- }
209
- function quoteNotRequired(path, line) {
210
- return BINARY.test(path) || NOTEBOOK.test(path) || MINIFIED.test(path) || line.length > 1e3;
211
- }
212
- var SECRET_PATH = [
213
- /(^|\/)\.env(\.|$)/i,
214
- /(^|\/)secrets?\//i,
215
- /(^|\/)credentials?(\.|$)/i,
216
- /\.(pem|key|p12|pfx|jks|keystore)$/i,
217
- /(^|\/)id_(rsa|ed25519|ecdsa|dsa)(\.|$)/i
218
- ];
219
- function isSecretPath(path) {
220
- const p2 = path.replace(/\\/g, "/").split("/").map((x) => x.replace(/:.*$/, "").replace(/[. ]+$/, "")).join("/");
221
- return SECRET_PATH.some((re) => re.test(p2));
222
- }
223
- var SECRET_KEY = /(password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|client[-_]?secret|credential)/i;
224
- var PLACEHOLDER = /^(\$\{|\{\{|env:|vault:|secret:|ref:|<)/;
225
- var KEY_VALUE = /^(\s*[-"']?\s*)([A-Za-z0-9_.:-]*?(?:password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|credentials?))(["']?\s*[:=]\s*)(.+)$/i;
226
- var SECRET_WORDS = "(?:password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|credentials?)";
227
- var KEY_LITERAL = new RegExp(`((?:^|[^A-Za-z0-9_.$-])[A-Za-z0-9_.$-]*?${SECRET_WORDS}["'\`]?\\]?(?:\\s*:\\s*[A-Za-z_][\\w.<>?\\[\\]]*(?=\\s*=))?\\s*(?::=|=>|=(?!=)|:(?!:))\\s*)(["'\`])((?:(?!\\2)[^\\\\]|\\\\.)+)\\2`, "i");
228
- var SETTER_LITERAL = new RegExp(`(\\b(?:set|with)[A-Za-z0-9_]*?${SECRET_WORDS}\\s*\\(\\s*)(["'\`])((?:(?!\\2)[^\\\\]|\\\\.)+)\\2`, "i");
229
- var KEY_BARE = new RegExp(`((?:\\bexport\\s+|--|[?&;])[A-Za-z0-9_.-]*?${SECRET_WORDS}\\s*=\\s*)([^\\s&;"'\`]+)`, "gi");
230
- var URL_CREDENTIALS = /\b([a-z][a-z0-9+.-]*:\/\/[^\s:@/]+:)([^\s@/]+)(?=@)/gi;
231
- var BEARER = /\b(Bearer\s+)([A-Za-z0-9._~+/-]{16,}=*)/g;
232
- var BASIC = /\b(Basic\s+)((?=[A-Za-z0-9+/]*[0-9+/=])[A-Za-z0-9+/]{12,}={0,2})/g;
233
- var TOKEN_SHAPES = [
234
- /\bgh[pousr]_[A-Za-z0-9]{20,}/g,
235
- /\bgithub_pat_[A-Za-z0-9_]{20,}/g,
236
- /\b(?:sk|rk)_(?:live|test)_[A-Za-z0-9]{8,}/g,
237
- /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
238
- /\bxox[abprs]-[A-Za-z0-9-]{10,}/g,
239
- /\bAIza[0-9A-Za-z_-]{35}/g,
240
- /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/g
241
- ];
242
- function hasSecretShape(text4, o = {}) {
243
- for (const m of text4.matchAll(URL_CREDENTIALS))
244
- if (!refersOnly(m[2]))
245
- return true;
246
- if (new RegExp(BEARER.source).test(text4))
247
- return true;
248
- if (o.basic !== false && new RegExp(BASIC.source).test(text4))
249
- return true;
250
- return TOKEN_SHAPES.some((re) => new RegExp(re.source).test(text4));
251
- }
252
- var placeholder = (v) => PLACEHOLDER.test(v.trim().replace(/^["'`]/, ""));
253
- var refersOnly = (v) => placeholder(v) || /^[$%{]/.test(v);
254
- function redactSecrets(line) {
255
- if (/-----BEGIN [A-Z ]*PRIVATE KEY-----/.test(line))
256
- return "<redacted>";
257
- let out = line;
258
- if (SECRET_KEY.test(out)) {
259
- const m = KEY_VALUE.exec(out);
260
- if (m && !placeholder(m[4]))
261
- out = `${m[1]}${m[2]}${m[3]}<redacted>`;
262
- for (const re of [KEY_LITERAL, SETTER_LITERAL]) {
263
- const k = re.exec(out);
264
- if (k && !placeholder(k[3]))
265
- out = `${out.slice(0, k.index)}${k[1]}<redacted>`;
266
- }
267
- out = out.replace(KEY_BARE, (all, key3, v) => refersOnly(v) || v === "<redacted>" ? all : `${key3}<redacted>`);
268
- }
269
- out = out.replace(URL_CREDENTIALS, (all, head, pass) => refersOnly(pass) ? all : `${head}<redacted>`);
270
- out = out.replace(BEARER, "$1<redacted>").replace(BASIC, "$1<redacted>");
271
- for (const re of TOKEN_SHAPES)
272
- out = out.replace(re, "<redacted>");
273
- return out;
274
- }
275
- var SECRET_IDENT = new RegExp(`[A-Za-z0-9_]*${SECRET_WORDS}[A-Za-z0-9_]*`, "i");
276
- var OPAQUE_LITERAL = /(["'`])([^\s"'`]{8,})\1/g;
277
- function quoteHoldsSecret(quote) {
278
- if (!SECRET_IDENT.test(quote))
279
- return false;
280
- for (const m of quote.matchAll(OPAQUE_LITERAL)) {
281
- const v = m[2];
282
- if (/^[/.#$%{<]/.test(v) || v.includes("://") || placeholder(v))
283
- continue;
284
- if (/[A-Za-z]/.test(v) && /[0-9]/.test(v))
285
- return true;
286
- }
287
- return false;
288
- }
289
- function defaultActionAt(lines, path) {
290
- if (path.split(/[?#]/, 1)[0].replace(/\/+/g, "") !== "")
291
- return false;
292
- const text4 = lines.join("\n");
293
- const mvc5 = /defaults:\s*new\s*\{[^}]*\}/.exec(text4)?.[0];
294
- if (!/MapDefaultControllerRoute|\{controller=\w+\}/.test(text4) && !mvc5)
295
- return false;
296
- const controller = /\{controller=(\w+)\}/.exec(text4)?.[1] ?? (mvc5 ? /controller\s*=\s*"(\w+)"/.exec(mvc5)?.[1] : void 0) ?? "Home";
297
- const action = /\{action=(\w+)\}/.exec(text4)?.[1] ?? (mvc5 ? /action\s*=\s*"(\w+)"/.exec(mvc5)?.[1] : void 0) ?? "Index";
298
- return new RegExp(`\\b${controller}Controller\\b`).test(text4) && new RegExp(`\\b${action}\\s*\\(`).test(text4);
299
- }
300
- var WORD_SEP = "[:._/#\\s]";
301
- function partsBuildWord(claim, parts, lines) {
302
- if (!parts.length)
303
- return false;
304
- let s = claim.trim();
305
- for (const raw of parts) {
306
- const v = raw.trim();
307
- if (!v)
308
- return false;
309
- const before = new RegExp(`^${WORD_SEP}`).test(v) ? "" : `(?<=^|${WORD_SEP}|\\u0000)`;
310
- const after = new RegExp(`${WORD_SEP}$`).test(v) ? "" : `(?=$|${WORD_SEP}|\\u0000)`;
311
- const re = new RegExp(`${before}${escape(v)}${after}`, "i");
312
- if (!re.test(s))
313
- return false;
314
- s = s.replace(re, "\0");
315
- }
316
- const edge = new RegExp(`^${WORD_SEP}+|${WORD_SEP}+$`, "g");
317
- const rest = s.split("\0").map((p2) => p2.replace(edge, "")).filter(Boolean);
318
- return rest.length > 0 && rest.every((p2) => lines.some((l) => lineNamesWord(l, p2)));
319
- }
320
- function partsNamePath(lines, path) {
321
- const parts = path.split(/[?#]/, 1)[0].split("/").filter((s) => s && !PARAM.test(s)).flatMap((s) => s.split(".")).filter(Boolean);
322
- if (!parts.length)
323
- return lines.some((l) => lineNamesRoute(l, path)) || defaultActionAt(lines, path);
324
- return parts.every((p2) => [p2, p2.replace(/-/g, "")].some((q2) => lines.some((l) => new RegExp(`(^|[^A-Za-z0-9]|(?<=[a-z0-9])(?=[A-Z]))${escape(q2)}`, "i").test(l))));
325
- }
326
-
327
136
  // packages/core/dist/schema/facts.js
328
137
  var str = () => external_exports.string().min(1);
329
138
  var FACT_KINDS = [
@@ -561,7 +370,7 @@ var SETTING_KINDS = [
561
370
  "config",
562
371
  "schedule"
563
372
  ];
564
- var SECRET_KEY2 = /(password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|credentials?)$/i;
373
+ var SECRET_KEY = /(password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|credentials?)$/i;
565
374
  var SECRET_SOURCE = /^(env:|vault:|secret:|ref:|\$\{|\{\{)/;
566
375
  var NOT_A_SECRET = /^(true|false|yes|no|on|off|include|omit|same-origin|none|null|\d+)$/i;
567
376
  function namesOfKey(key3) {
@@ -571,7 +380,7 @@ function namesOfKey(key3) {
571
380
  return [lastOf(bare), ...bracketed.map(lastOf)].filter(Boolean);
572
381
  }
573
382
  function looksLikeSecret(key3, value) {
574
- return value !== void 0 && namesOfKey(key3).some((n) => SECRET_KEY2.test(n)) && !SECRET_SOURCE.test(value) && !NOT_A_SECRET.test(value.trim());
383
+ return value !== void 0 && namesOfKey(key3).some((n) => SECRET_KEY.test(n)) && !SECRET_SOURCE.test(value) && !NOT_A_SECRET.test(value.trim());
575
384
  }
576
385
  var tokenLike = (t) => /^[A-Za-z0-9+/=_.~-]{6,}$/.test(t) && /[0-9]/.test(t) && /[A-Za-z]/.test(t) && !/\.[a-z]{2,5}$/i.test(t) && !pathOfNames(t);
577
386
  var pathOfNames = (t) => t.startsWith("/") || t.includes("/") && t.split("/").every((s) => s === "" || NAME_LIKE.some((r) => r.test(s)) || identifierName(s) || fileName(s));
@@ -2294,7 +2103,9 @@ var FACTS_COMPANIONS = [
2294
2103
  // ADR 0164: the specs (OpenAPI, .proto, Avro, JSON Schema, AsyncAPI) read in the repo at the facts' commit.
2295
2104
  ".specs.yaml",
2296
2105
  // ADR 0157: the prompt for a second pass on the gaps the last verify listed.
2297
- ".gaps.md"
2106
+ ".gaps.md",
2107
+ // ADR 0195 point 3: a person's dismissals of what the readers found.
2108
+ ".crosscheck.yaml"
2298
2109
  ];
2299
2110
  function factsFileOf(name) {
2300
2111
  for (const c of FACTS_COMPANIONS)
@@ -2529,6 +2340,11 @@ async function addManifestRepos(root, platform, entries, o = {}) {
2529
2340
  return { file, changes, written: true };
2530
2341
  }
2531
2342
  async function renameManifestRepo(root, repo, to) {
2343
+ const r = await renamedManifest(root, repo, to);
2344
+ await writeFileIfUnchanged(r.file.path, r.text, r.next);
2345
+ return r.file;
2346
+ }
2347
+ async function renamedManifest(root, repo, to) {
2532
2348
  for (const other of await manifestFiles(root)) {
2533
2349
  const t = await readFile(other.path, "utf8").catch(() => void 0);
2534
2350
  if (t === void 0)
@@ -2541,8 +2357,11 @@ async function renameManifestRepo(root, repo, to) {
2541
2357
  if (!found)
2542
2358
  throw new ManifestEditError("not-found", `There is no repo ${repo} in any manifest.`);
2543
2359
  found.item.set("id", to);
2544
- await save(found.file.path, found.doc, found.text);
2545
- return found.file;
2360
+ const check = RepoManifest.safeParse(found.doc.toJS());
2361
+ if (!check.success)
2362
+ throw new ManifestEditError("invalid", check.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; "));
2363
+ const next = inEol(found.doc.toString({ lineWidth: 0, flowCollectionPadding: true }), eolOf(found.text));
2364
+ return { file: found.file, text: found.text, next };
2546
2365
  }
2547
2366
  async function migrateManifests(root, o = {}) {
2548
2367
  const to = o.to ?? WORKSPACE_SCHEMA_VERSION;
@@ -2763,7 +2582,7 @@ function systemNameProblem(name) {
2763
2582
  return void 0;
2764
2583
  }
2765
2584
  async function knownTargetNames(root, o = {}) {
2766
- const { loadOrgPack } = await import("./chunk-3D74UADA.js");
2585
+ const { loadOrgPack } = await import("./chunk-NGSGJLKW.js");
2767
2586
  const op = await loadOrgPack(orgPackDirOf(root)).catch(() => void 0);
2768
2587
  const ids = /* @__PURE__ */ new Set();
2769
2588
  const names = /* @__PURE__ */ new Set();
@@ -3126,18 +2945,18 @@ var isShortServiceHost = (host) => !host.replace(/:\d+$/, "").includes(".");
3126
2945
  var PATH_PATTERN = /[()[\]|$^*+?\\]/;
3127
2946
  var isPatternPath = (path) => PATH_PATTERN.test(path);
3128
2947
  function plainPathPrefix(path) {
3129
- const segs2 = [];
2948
+ const segs3 = [];
3130
2949
  for (const s of path.split("/").filter(Boolean)) {
3131
2950
  const at3 = s.search(PATH_PATTERN);
3132
2951
  if (at3 < 0) {
3133
- segs2.push(s);
2952
+ segs3.push(s);
3134
2953
  continue;
3135
2954
  }
3136
2955
  if (at3 > 0)
3137
- segs2.push(s.slice(0, at3));
2956
+ segs3.push(s.slice(0, at3));
3138
2957
  break;
3139
2958
  }
3140
- return `/${segs2.join("/")}`;
2959
+ return `/${segs3.join("/")}`;
3141
2960
  }
3142
2961
  var JOINED_BY_PATH = "joined-by-path";
3143
2962
  var JOINED_BY_LABEL = "joined-by-label";
@@ -3275,10 +3094,11 @@ function callTargetQuestion(f, component) {
3275
3094
  const what2 = [f.method?.toUpperCase(), f.path].filter(Boolean).join(" ");
3276
3095
  return `Which repo or system answers ${what2}, which ${component} calls${f.base ? ` through ${f.base}` : ""}?`;
3277
3096
  }
3278
- function forwardHostQuestion(host, repo) {
3097
+ function forwardHostQuestion(host, repo, prefix) {
3279
3098
  if (!placeholderIn(host))
3280
3099
  return hostQuestionText(host);
3281
- return `Which repo answers on ${host}? ${repo}'s target URL is a token no fact sets. If a deploy file sets it per environment (the Apigee config plugin's config.json), read ${repo} again with your assistant (Read with my assistant): the read records each environment's value, and the calls join where they go. Else name the repo or the outside system that answers.`;
3100
+ const routes = prefix ? ` for the routes under ${prefix === "/" ? "" : prefix}/**` : "";
3101
+ return `Which repo answers on ${host}? ${repo}'s target URL${routes} is a token no fact sets. If a deploy file sets it per environment (the Apigee config plugin's config.json), read ${repo} again with your assistant (Read with my assistant): the read records each environment's value, and the calls join where they go. Else name the repo or the outside system that answers.`;
3282
3102
  }
3283
3103
  function gatewayCycleQuestion(f, component, gateway) {
3284
3104
  const what2 = [f.method?.toUpperCase(), f.path].filter(Boolean).join(" ");
@@ -3288,8 +3108,8 @@ var SECRETISH = /^(env:|vault:|secret:|ref:|\$\{|\{\{)/i;
3288
3108
  function pathSegments(p2) {
3289
3109
  if (!p2)
3290
3110
  return void 0;
3291
- const segs2 = p2.split(/[?#]/)[0].split("/").filter(Boolean).map((x) => /^\{[^}]*\}$/.test(x) ? "{}" : x.toLowerCase());
3292
- return segs2.length ? segs2 : void 0;
3111
+ const segs3 = p2.split(/[?#]/)[0].split("/").filter(Boolean).map((x) => /^\{[^}]*\}$/.test(x) ? "{}" : x.toLowerCase());
3112
+ return segs3.length ? segs3 : void 0;
3293
3113
  }
3294
3114
  var sameSegment = (a, b) => a === "{}" || b === "{}" || a === b;
3295
3115
  var sameSegments = (a, b) => (a?.length ?? 0) === (b?.length ?? 0) && (a ?? []).every((x, i) => sameSegment(x, b[i]));
@@ -3597,7 +3417,7 @@ function joinFacts(input) {
3597
3417
  return !!deploysIn.get(key3(t.repo, t.fact.cite.file))?.has(name);
3598
3418
  });
3599
3419
  };
3600
- const resolve3 = (raw, owner, seen, depth = 0) => {
3420
+ const resolve3 = (raw, owner, seen, depth = 0, own = false) => {
3601
3421
  const v = raw?.trim();
3602
3422
  if (!v)
3603
3423
  return [];
@@ -3607,8 +3427,8 @@ function joinFacts(input) {
3607
3427
  if (depth >= MAX_PLACEHOLDER_DEPTH)
3608
3428
  return [];
3609
3429
  if (placeholderIn(p2.after)) {
3610
- const head = resolve3(v.slice(0, v.length - p2.after.length), owner, seen, depth);
3611
- const tail = resolve3(p2.after, owner, seen, depth);
3430
+ const head = resolve3(v.slice(0, v.length - p2.after.length), owner, seen, depth, own);
3431
+ const tail = resolve3(p2.after, owner, seen, depth, own);
3612
3432
  if (new Set(head.map((r) => r.value)).size !== 1)
3613
3433
  return [];
3614
3434
  if (new Set(tail.map((r) => r.value)).size !== 1)
@@ -3626,10 +3446,12 @@ function joinFacts(input) {
3626
3446
  const named = (configsByName.get(want) ?? []).filter((s) => !seen.has(key3(s.repo, s.fact.id)));
3627
3447
  const mine = named.flatMap((s) => {
3628
3448
  const how = setsFor(s, owner);
3449
+ if (own && how !== "cited")
3450
+ return [];
3629
3451
  const guess = how === "folder" ? [JOINED_BY_FOLDER_NAME] : [];
3630
3452
  return how ? [{ s, guess }] : [];
3631
3453
  });
3632
- const settings = mine.length ? mine : named.filter((x) => setsForAll(x, owner)).map((s) => ({ s, guess: [JOINED_BY_PLATFORM_SETTING] }));
3454
+ const settings = mine.length || own ? mine : named.filter((x) => setsForAll(x, owner)).map((s) => ({ s, guess: [JOINED_BY_PLATFORM_SETTING] }));
3633
3455
  const viaRef = new Set(settings.flatMap(({ s }) => refTargets(s, owner, seen).map((t) => key3(t.repo, t.fact.id))));
3634
3456
  for (const { s, guess } of settings.filter(({ s: x }) => !viaRef.has(key3(x.repo, x.fact.id)))) {
3635
3457
  const k = key3(s.repo, s.fact.id);
@@ -3637,7 +3459,7 @@ function joinFacts(input) {
3637
3459
  if (ref2) {
3638
3460
  for (const t of refTargets(s, owner, seen)) {
3639
3461
  const tv = t.fact.value?.trim() ?? "";
3640
- const rs = ref2.secret ? PLAIN_HOST.test(tv) ? [{ value: tv, through: [], guesses: [] }] : [] : resolve3(t.fact.value, owner, /* @__PURE__ */ new Set([...seen, k, key3(t.repo, t.fact.id)]), depth + 1);
3462
+ const rs = ref2.secret ? PLAIN_HOST.test(tv) ? [{ value: tv, through: [], guesses: [] }] : [] : resolve3(t.fact.value, owner, /* @__PURE__ */ new Set([...seen, k, key3(t.repo, t.fact.id)]), depth + 1, own);
3641
3463
  for (const r of rs)
3642
3464
  out.push({
3643
3465
  value: `${p2.before}${r.value}${p2.after}`,
@@ -3647,7 +3469,7 @@ function joinFacts(input) {
3647
3469
  }
3648
3470
  continue;
3649
3471
  }
3650
- for (const r of resolve3(s.fact.value ?? s.fact.source, owner, /* @__PURE__ */ new Set([...seen, k]), depth + 1))
3472
+ for (const r of resolve3(s.fact.value ?? s.fact.source, owner, /* @__PURE__ */ new Set([...seen, k]), depth + 1, own))
3651
3473
  out.push({
3652
3474
  value: `${p2.before}${r.value}${p2.after}`,
3653
3475
  through: [s, ...r.through],
@@ -3656,7 +3478,7 @@ function joinFacts(input) {
3656
3478
  }
3657
3479
  if (out.length || !p2.fallback)
3658
3480
  return out;
3659
- return resolve3(p2.fallback, owner, seen, depth + 1).map((r) => ({
3481
+ return resolve3(p2.fallback, owner, seen, depth + 1, own).map((r) => ({
3660
3482
  ...r,
3661
3483
  value: `${p2.before}${r.value}${p2.after}`
3662
3484
  }));
@@ -3696,8 +3518,8 @@ function joinFacts(input) {
3696
3518
  };
3697
3519
  const ownNamespaces = [];
3698
3520
  const addPath = (g, path, by) => {
3699
- const segs2 = pathSegments(path);
3700
- const h = g.paths.find((x) => sameSegments(pathSegments(x.path), segs2));
3521
+ const segs3 = pathSegments(path);
3522
+ const h = g.paths.find((x) => sameSegments(pathSegments(x.path), segs3));
3701
3523
  if (h) {
3702
3524
  if (by)
3703
3525
  h.by.push(by);
@@ -3826,8 +3648,8 @@ function joinFacts(input) {
3826
3648
  const listed = ported.length ? ported : declared.filter((d) => !hostHasPort(d.pattern) && hostMatches(d.pattern, h.host, h.port));
3827
3649
  if (!listed.length)
3828
3650
  return void 0;
3829
- const segs2 = pathSegments(path) ?? [];
3830
- const starts = listed.filter((d) => d.basePath && d.basePath.length <= segs2.length && d.basePath.every((x, i) => sameSegment(x, segs2[i])));
3651
+ const segs3 = pathSegments(path) ?? [];
3652
+ const starts = listed.filter((d) => d.basePath && d.basePath.length <= segs3.length && d.basePath.every((x, i) => sameSegment(x, segs3[i])));
3831
3653
  const longest2 = Math.max(0, ...starts.map((d) => d.basePath.length));
3832
3654
  const all = starts.length ? starts.filter((d) => d.basePath.length === longest2) : listed.filter((d) => !d.basePath);
3833
3655
  if (!all.length)
@@ -3886,32 +3708,32 @@ function joinFacts(input) {
3886
3708
  byLastLiteral.set(k, [e]);
3887
3709
  };
3888
3710
  for (const e of entries) {
3889
- const segs2 = segments(e.fact.path);
3890
- if (!segs2)
3711
+ const segs3 = segments(e.fact.path);
3712
+ if (!segs3)
3891
3713
  continue;
3892
- if (segs2.includes("**")) {
3714
+ if (segs3.includes("**")) {
3893
3715
  withCatchAll.push(e);
3894
3716
  continue;
3895
3717
  }
3896
- if (!segs2.length) {
3718
+ if (!segs3.length) {
3897
3719
  push2("/", e);
3898
3720
  continue;
3899
3721
  }
3900
- for (let k = 0; k < segs2.length; k++)
3901
- if (literal(segs2[segs2.length - 1 - k])) {
3902
- push2(`${k}\0${segs2[segs2.length - 1 - k]}`, e);
3722
+ for (let k = 0; k < segs3.length; k++)
3723
+ if (literal(segs3[segs3.length - 1 - k])) {
3724
+ push2(`${k}\0${segs3[segs3.length - 1 - k]}`, e);
3903
3725
  break;
3904
3726
  }
3905
3727
  }
3906
3728
  const routeCandidates = (path) => {
3907
- const segs2 = segments(path);
3908
- if (!segs2)
3729
+ const segs3 = segments(path);
3730
+ if (!segs3)
3909
3731
  return [];
3910
3732
  const got = [...withCatchAll];
3911
- if (!segs2.length)
3733
+ if (!segs3.length)
3912
3734
  got.push(...byLastLiteral.get("/") ?? []);
3913
- for (let k = 0; k < segs2.length; k++) {
3914
- const s = segs2[segs2.length - 1 - k];
3735
+ for (let k = 0; k < segs3.length; k++) {
3736
+ const s = segs3[segs3.length - 1 - k];
3915
3737
  if (literal(s))
3916
3738
  got.push(...byLastLiteral.get(`${k}\0${s}`) ?? []);
3917
3739
  }
@@ -3977,7 +3799,7 @@ function joinFacts(input) {
3977
3799
  return hs;
3978
3800
  };
3979
3801
  const rawSegs = (p2) => (p2.trim().split(/[?#]/, 1)[0] ?? "").split("/").filter((s) => s.length > 0);
3980
- const toPath = (segs2) => `/${segs2.join("/")}`;
3802
+ const toPath = (segs3) => `/${segs3.join("/")}`;
3981
3803
  const segKey = (s) => segments(`/${s}`)?.[0] ?? s;
3982
3804
  const startsWithSegs = (a, b) => b.length <= a.length && b.every((x, i) => sameSegment(segKey(x), segKey(a[i])));
3983
3805
  const endsWithSegs = (a, b) => startsWithSegs(a.slice(a.length - b.length), b) && b.length <= a.length;
@@ -4034,9 +3856,9 @@ function joinFacts(input) {
4034
3856
  const servlets = valuesOf(SERVLET_PATH_KEYS);
4035
3857
  for (const c of contexts.length ? contexts : none)
4036
3858
  for (const s of servlets.length ? servlets : none) {
4037
- const segs2 = [...c.segs, ...s.segs];
4038
- if (segs2.length)
4039
- out.push({ from: "config", segs: segs2, by: [...c.by, ...s.by] });
3859
+ const segs3 = [...c.segs, ...s.segs];
3860
+ if (segs3.length)
3861
+ out.push({ from: "config", segs: segs3, by: [...c.by, ...s.by] });
4040
3862
  }
4041
3863
  basesSeen.set(k, out);
4042
3864
  return out;
@@ -4084,13 +3906,13 @@ function joinFacts(input) {
4084
3906
  const out = [];
4085
3907
  for (const x of tried) {
4086
3908
  const method = [f.method, x.route?.fact.method].find((m) => !!m && m.toUpperCase() !== "ANY")?.toUpperCase();
4087
- const score = (segs2, e) => {
3909
+ const score = (segs3, e) => {
4088
3910
  if (!x.under) {
4089
- const s = routeScore(toPath(segs2), e.path);
3911
+ const s = routeScore(toPath(segs3), e.path);
4090
3912
  return s >= 400 ? s : 0;
4091
3913
  }
4092
3914
  const es = rawSegs(e.path);
4093
- return es.includes("**") || !startsWithSegs(es, segs2) ? 0 : 1;
3915
+ return es.includes("**") || !startsWithSegs(es, segs3) ? 0 : 1;
4094
3916
  };
4095
3917
  const hits = [];
4096
3918
  for (const e of x.under ? entries : routeCandidates(toPath(x.segs))) {
@@ -4151,9 +3973,10 @@ function joinFacts(input) {
4151
3973
  from: b.from,
4152
3974
  ...b.by.length ? { by: uniqueEnds(b.by) } : {}
4153
3975
  });
4154
- const replacedFor = (call) => {
3976
+ const replacedFor = (call, token) => {
3977
+ const written = call.fact.host ?? call.fact.base ?? token;
4155
3978
  const parts = [call.fact.cite, ...call.fact.cite.with ?? []];
4156
- const urlText = (call.fact.host ?? call.fact.base ?? "").trim();
3979
+ const urlText = (written ?? "").trim();
4157
3980
  const writing = urlText ? parts.filter((p2) => p2.value.trim() === urlText) : [];
4158
3981
  const cited = (writing.length ? writing : parts).map((p2) => p2.file);
4159
3982
  const rootFits = (file, xpath) => {
@@ -4177,7 +4000,7 @@ function joinFacts(input) {
4177
4000
  const home = bundleHomeOf(call.fact.cite.file);
4178
4001
  const homes = home === void 0 ? void 0 : bundleHomesOf(call.repo);
4179
4002
  const ownedBy = (file) => homes.filter((h) => file.startsWith(h)).sort((a, b) => b.length - a.length)[0] ?? (homes.length === 1 ? homes[0] : void 0);
4180
- const wanted = placeholderIn(call.fact.host ?? call.fact.base)?.name;
4003
+ const wanted = placeholderIn(written)?.name;
4181
4004
  const tokenNames = (n) => [n.fact.source, ...(n.fact.cite.with ?? []).map((w) => w.value)].flatMap((v) => {
4182
4005
  const p2 = v && /^\s*(@[^@\s]+@|\{\{[^}]+\}\})\s*$/.test(v) ? placeholderIn(v) : void 0;
4183
4006
  return p2 ? [p2.name] : [];
@@ -4226,7 +4049,7 @@ function joinFacts(input) {
4226
4049
  return !served;
4227
4050
  };
4228
4051
  const targetServed = /* @__PURE__ */ new Map();
4229
- const genericBase = (segs2) => segs2.every((s) => /^(v\d+(\.\d+)*|api|rest|services)$/i.test(s));
4052
+ const genericBase = (segs3) => segs3.every((s) => /^(v\d+(\.\d+)*|api|rest|services)$/i.test(s));
4230
4053
  const ownBaseSeen = /* @__PURE__ */ new Map();
4231
4054
  let baseOwners;
4232
4055
  const ownersOfBases = () => {
@@ -4244,10 +4067,10 @@ function joinFacts(input) {
4244
4067
  return baseOwners;
4245
4068
  };
4246
4069
  const isOwnBase = (component, p2) => {
4247
- const segs2 = rawSegs(p2);
4248
- if (genericBase(segs2))
4070
+ const segs3 = rawSegs(p2);
4071
+ if (genericBase(segs3))
4249
4072
  return false;
4250
- const k = `${component}\0${segs2.join("/").toLowerCase()}`;
4073
+ const k = `${component}\0${segs3.join("/").toLowerCase()}`;
4251
4074
  const was = ownBaseSeen.get(k);
4252
4075
  if (was !== void 0)
4253
4076
  return was;
@@ -4260,7 +4083,7 @@ function joinFacts(input) {
4260
4083
  if (done.has(ek))
4261
4084
  continue;
4262
4085
  done.add(ek);
4263
- if (basesOf(e).some((b) => b.segs.length === segs2.length && startsWithSegs(segs2, b.segs))) {
4086
+ if (basesOf(e).some((b) => b.segs.length === segs3.length && startsWithSegs(segs3, b.segs))) {
4264
4087
  got = true;
4265
4088
  break;
4266
4089
  }
@@ -4273,7 +4096,7 @@ function joinFacts(input) {
4273
4096
  return true;
4274
4097
  if (call.fact.callType !== "rest")
4275
4098
  return false;
4276
- const segs2 = rawSegs(p2);
4099
+ const segs3 = rawSegs(p2);
4277
4100
  return routeCandidates(p2).some((e) => {
4278
4101
  if (e.component === call.component || !SERVES.rest.includes(e.fact.entryType) || !sameMethod(call.fact.method, e.fact.method))
4279
4102
  return false;
@@ -4281,11 +4104,26 @@ function joinFacts(input) {
4281
4104
  if (gatewayRoute && isPassThrough(e.fact))
4282
4105
  return false;
4283
4106
  const least = gatewayRoute ? 400 : 100;
4284
- return basesOf(e).some((b) => b.segs.length > 0 && b.segs.length < segs2.length && startsWithSegs(segs2, b.segs) && routeScore(toPath(segs2.slice(b.segs.length)), e.fact.path) >= least);
4107
+ return basesOf(e).some((b) => b.segs.length > 0 && b.segs.length < segs3.length && startsWithSegs(segs3, b.segs) && routeScore(toPath(segs3.slice(b.segs.length)), e.fact.path) >= least);
4285
4108
  });
4286
4109
  };
4287
4110
  const gatewayRepos = new Set(repos.filter((r) => r.gateway).map((r) => r.repo));
4288
4111
  const isForwarding = (c) => c.fact.callType === "rest" && (!!bundleRootOf(c.fact.cite.file) || gatewayRepos.has(c.repo));
4112
+ const forwardTokenOf = (c) => {
4113
+ if (c.fact.host || c.fact.base || !isForwarding(c))
4114
+ return void 0;
4115
+ const said = new Set([c.fact.cite.value, ...(c.fact.cite.with ?? []).map((w) => w.value)].flatMap((raw) => {
4116
+ const v = raw.trim();
4117
+ const p2 = placeholderIn(v);
4118
+ if (!p2 || hostIn(v))
4119
+ return [];
4120
+ const before = p2.before.trim();
4121
+ if (before && !/^[a-z][a-z0-9+.-]*:\/\/$/i.test(before))
4122
+ return [];
4123
+ return p2.after === "" || /^[/:?]/.test(p2.after) ? [v] : [];
4124
+ }));
4125
+ return said.size === 1 ? [...said][0] : void 0;
4126
+ };
4289
4127
  const proxyOf = (r) => key3(r.repo, bundleRootOf(r.fact.cite.file) ?? r.fact.handler?.split("/")[0] ?? "");
4290
4128
  let baseRoutes;
4291
4129
  const baseRoutesOf = () => {
@@ -4317,18 +4155,18 @@ function joinFacts(input) {
4317
4155
  return baseRoutes;
4318
4156
  };
4319
4157
  const byBasePath = (c, path) => {
4320
- const segs2 = rawSegs(path);
4321
- if (!segs2.length)
4158
+ const segs3 = rawSegs(path);
4159
+ if (!segs3.length)
4322
4160
  return void 0;
4323
4161
  const { byFirst, all } = baseRoutesOf();
4324
- const first = segKey(segs2[0]);
4162
+ const first = segKey(segs3[0]);
4325
4163
  const pool = first === "{}" ? all : [...byFirst.get(first) ?? [], ...byFirst.get("{}") ?? []];
4326
4164
  const ownBundle = bundleRootOf(c.fact.cite.file);
4327
- const under2 = pool.filter((x) => (x.r.component !== c.component || !!ownBundle && proxyOf(x.r) !== key3(c.repo, ownBundle)) && x.base.length < segs2.length && startsWithSegs(segs2, x.base));
4328
- if (!under2.length)
4165
+ const under3 = pool.filter((x) => (x.r.component !== c.component || !!ownBundle && proxyOf(x.r) !== key3(c.repo, ownBundle)) && x.base.length < segs3.length && startsWithSegs(segs3, x.base));
4166
+ if (!under3.length)
4329
4167
  return void 0;
4330
- const longest2 = Math.max(...under2.map((x) => x.base.length));
4331
- const top = under2.filter((x) => x.base.length === longest2).map((x) => x.r);
4168
+ const longest2 = Math.max(...under3.map((x) => x.base.length));
4169
+ const top = under3.filter((x) => x.base.length === longest2).map((x) => x.r);
4332
4170
  if (new Set(top.map(proxyOf)).size !== 1)
4333
4171
  return void 0;
4334
4172
  const scored = top.filter((r) => sameMethod(c.fact.method, r.fact.method) && !isPassThrough(r.fact)).map((r) => ({ r, score: routeScore(path, r.fact.path) })).filter((x) => x.score >= 400);
@@ -4336,7 +4174,7 @@ function joinFacts(input) {
4336
4174
  return void 0;
4337
4175
  const best = Math.max(...scored.map((x) => x.score));
4338
4176
  const flows = scored.filter((x) => x.score === best).map((x) => x.r).sort((x, y) => cmp(x.repo, y.repo) || cmp(x.fact.id, y.fact.id));
4339
- const routed = new Set(under2.map((x) => x.r));
4177
+ const routed = new Set(under3.map((x) => x.r));
4340
4178
  const others = serving({ ...c, fact: { ...c.fact, path } }, (e) => !routed.has(e), true);
4341
4179
  return { flows, others };
4342
4180
  };
@@ -4388,17 +4226,20 @@ function joinFacts(input) {
4388
4226
  }
4389
4227
  const keyed = f.base ? (configsByRepo.get(call.repo) ?? []).filter((n) => n.fact.key === f.base) : [];
4390
4228
  const cands = [];
4229
+ const token = forwardTokenOf(call);
4230
+ const fHost = f.host ?? token;
4231
+ const own = isForwarding(call) && !!bundleRootOf(f.cite.file) && TOKEN_FORMS.some((re) => re.test(fHost ?? f.base ?? ""));
4391
4232
  if (!hostIn(f.host)) {
4392
- if (placeholderIn(f.host))
4393
- cands.push(...resolve3(f.host, call, /* @__PURE__ */ new Set()));
4233
+ if (placeholderIn(fHost))
4234
+ cands.push(...resolve3(fHost, call, /* @__PURE__ */ new Set(), 0, own));
4394
4235
  else if (keyed.length)
4395
4236
  for (const t of keyed)
4396
4237
  for (const r of resolve3(t.fact.value ?? t.fact.source, call, /* @__PURE__ */ new Set([key3(t.repo, t.fact.id)])))
4397
4238
  cands.push({ ...r, tie: t });
4398
4239
  else if (placeholderIn(f.base))
4399
- cands.push(...resolve3(f.base, call, /* @__PURE__ */ new Set()));
4240
+ cands.push(...resolve3(f.base, call, /* @__PURE__ */ new Set(), 0, own));
4400
4241
  if (!cands.some((x) => !!hostIn(x.value)))
4401
- cands.push(...replacedFor(call));
4242
+ cands.push(...replacedFor(call, token));
4402
4243
  }
4403
4244
  const configs = cands.filter((x) => !!hostIn(x.value));
4404
4245
  const claimOf2 = (x) => claimed(hostIn(x.value), joinPaths(urlPathOf(x.value), f.path));
@@ -4415,7 +4256,7 @@ function joinFacts(input) {
4415
4256
  if (host)
4416
4257
  return void 0;
4417
4258
  if (!keyed.length)
4418
- return pathAroundPlaceholder(f.host) ?? pathAroundPlaceholder(f.base);
4259
+ return pathAroundPlaceholder(fHost) ?? pathAroundPlaceholder(f.base);
4419
4260
  const ps = new Set(keyed.map((t) => pathAroundPlaceholder(t.fact.value ?? t.fact.source)));
4420
4261
  return ps.size === 1 ? [...ps][0] : void 0;
4421
4262
  };
@@ -4561,9 +4402,9 @@ function joinFacts(input) {
4561
4402
  continue;
4562
4403
  }
4563
4404
  const forwarding = isForwarding(call);
4564
- const namesHost = !!(f.host || f.base);
4405
+ const namesHost = !!(f.host || f.base || token);
4565
4406
  if (forwarding && namesHost) {
4566
- const named2 = f.host ?? f.base;
4407
+ const named2 = f.host ?? f.base ?? token;
4567
4408
  asks.push({
4568
4409
  call: end(call),
4569
4410
  reason: "unknown-host",
@@ -4980,9 +4821,9 @@ function gatewayRouteId(n) {
4980
4821
  return fitId(id, `gw-${n.component}`).replace(/\./g, "-");
4981
4822
  }
4982
4823
  function basePathOf(e) {
4983
- const segs2 = (p2) => p2.split(/[?#]/, 1)[0].split("/").filter(Boolean);
4984
- const path = segs2(e.path);
4985
- const base = (e.cite.with ?? []).map((p2) => segs2(p2.value)).filter((s) => s.length > 0 && s.length < path.length && s.every((x, k) => x === path[k])).sort((a, b) => b.length - a.length)[0];
4824
+ const segs3 = (p2) => p2.split(/[?#]/, 1)[0].split("/").filter(Boolean);
4825
+ const path = segs3(e.path);
4826
+ const base = (e.cite.with ?? []).map((p2) => segs3(p2.value)).filter((s) => s.length > 0 && s.length < path.length && s.every((x, k) => x === path[k])).sort((a, b) => b.length - a.length)[0];
4986
4827
  return base ? `/${base.join("/")}` : e.path;
4987
4828
  }
4988
4829
  function joinGuessesOf(j) {
@@ -5305,6 +5146,52 @@ function joinRecords(result, repos) {
5305
5146
  var cmp2 = (a, b) => a < b ? -1 : a > b ? 1 : 0;
5306
5147
  var compact = (x) => x.toLowerCase().replace(/[^a-z0-9]/g, "");
5307
5148
  var SECRETISH2 = /^(env:|vault:|secret:|ref:|\$\{|\{\{)/i;
5149
+ function urlPathOf2(s) {
5150
+ const m = s ? /^[a-z][a-z0-9+.-]*:\/\/[^/?#]+(\/[^?#]*)/i.exec(s.trim()) : null;
5151
+ const p2 = m?.[1]?.replace(/\/+$/, "");
5152
+ return p2 ? p2 : void 0;
5153
+ }
5154
+ var PROD_LIKE = /(^|[^a-z])(pd|prod|prd|production)([^a-z]|$)/i;
5155
+ function preferredEnvironment(envs) {
5156
+ const named = [...new Set(envs.filter(Boolean))].sort(cmp2);
5157
+ return named.find((e) => PROD_LIKE.test(e) && !NOT_PROD.test(e)) ?? named[0];
5158
+ }
5159
+ var NOT_PROD = /(^|[^a-z])(non|pre|np)[-_ ]?(pd|prod|prd|production)([^a-z]|$)/i;
5160
+ function under(prefix, path) {
5161
+ const p2 = path.startsWith("/") ? path : `/${path}`;
5162
+ if (!prefix)
5163
+ return p2;
5164
+ const lower2 = p2.toLowerCase();
5165
+ const pre = prefix.toLowerCase();
5166
+ return lower2 === pre || lower2.startsWith(`${pre}/`) ? p2 : `${prefix}${p2 === "/" ? "" : p2}`;
5167
+ }
5168
+ function segs(path) {
5169
+ const p2 = (path.trim().split(/[?#]/, 1)[0] ?? "").replace(/\{([^}:?]*)[^}]*\}/g, "{$1}");
5170
+ if (!p2.startsWith("/"))
5171
+ return void 0;
5172
+ return p2.split("/").filter(Boolean).map((s) => /^(\{\*[^}]*\}|\*\*|\{\*\*\})$/.test(s) ? "**" : s === "*" ? "*" : /^(\{[^}]*\}|:[^/]+|<[^>]+>|\$\{[^}]*\})$/.test(s) ? "{}" : s.toLowerCase());
5173
+ }
5174
+ function fit(call, op) {
5175
+ const rest = call.indexOf("**");
5176
+ const head = rest >= 0 ? call.slice(0, rest) : call;
5177
+ if (rest >= 0 ? op.length < head.length : op.length !== call.length)
5178
+ return void 0;
5179
+ let literals = 0;
5180
+ let wildcard = rest >= 0;
5181
+ for (let i = 0; i < head.length; i++) {
5182
+ const a = head[i];
5183
+ const b = op[i];
5184
+ if (a === "*")
5185
+ wildcard = true;
5186
+ else if (b === "{}")
5187
+ continue;
5188
+ else if (a === b)
5189
+ literals++;
5190
+ else
5191
+ return void 0;
5192
+ }
5193
+ return literals > 0 ? { literals, wildcard } : void 0;
5194
+ }
5308
5195
  function hostOf(s) {
5309
5196
  const t = s?.trim();
5310
5197
  if (!t || SECRETISH2.test(t))
@@ -5315,6 +5202,22 @@ function hostOf(s) {
5315
5202
  const m = /^([a-z0-9][a-z0-9.-]*)(?::(\d+))?$/i.exec(t);
5316
5203
  return m ? { host: m[1].toLowerCase(), ...m[2] ? { port: Number(m[2]) } : {} } : void 0;
5317
5204
  }
5205
+ function tokenOf(call, forwarding) {
5206
+ const whole = (v) => {
5207
+ const t = v?.trim();
5208
+ const p2 = t ? placeholderIn(t) : void 0;
5209
+ return p2 && !p2.before.trim() && (p2.after === "" || /^[/:?]/.test(p2.after)) ? t : void 0;
5210
+ };
5211
+ if (call.host)
5212
+ return whole(call.host);
5213
+ if (call.base || !forwarding)
5214
+ return void 0;
5215
+ const said = new Set([call.cite.value, ...(call.cite.with ?? []).map((w) => w.value)].flatMap((v) => {
5216
+ const t = whole(v);
5217
+ return t ? [t] : [];
5218
+ }));
5219
+ return said.size === 1 ? [...said][0] : void 0;
5220
+ }
5318
5221
  var takesDirect = (v) => v.boundary === "internal";
5319
5222
  var sameMethod2 = (a, b) => {
5320
5223
  const x = a?.toUpperCase();
@@ -5336,7 +5239,14 @@ function joinVendorOperations(input) {
5336
5239
  if (k.length >= 3)
5337
5240
  byLabel.set(k, (byLabel.get(k) ?? /* @__PURE__ */ new Set()).add(v));
5338
5241
  }
5242
+ const estateHosts = input.repos.flatMap((r) => [
5243
+ ...r.hosts ?? [],
5244
+ ...(r.modules ?? []).flatMap((m) => m.hosts)
5245
+ ]);
5246
+ const joinedCalls = new Set((input.joined ?? []).map((j) => `${j.call.repo}\0${j.call.fact}`));
5339
5247
  const vendorOfHost = (h) => {
5248
+ if (estateHosts.some((p2) => hostMatches(p2, h.host, h.port)))
5249
+ return void 0;
5340
5250
  const listed = vendors.filter((v) => v.hosts.some((p2) => hostMatches(p2, h.host, h.port)));
5341
5251
  if (listed.length === 1)
5342
5252
  return listed[0];
@@ -5371,9 +5281,22 @@ function joinVendorOperations(input) {
5371
5281
  continue;
5372
5282
  const call = f;
5373
5283
  const route = routeFact ? end(routeFact) : void 0;
5284
+ if (joinedCalls.has(`${r.repo}\0${call.id}`))
5285
+ continue;
5374
5286
  let vendor;
5375
5287
  let how;
5376
5288
  let tie;
5289
+ const direct = hostOf(call.host);
5290
+ const token = direct ? void 0 : tokenOf(call, forwarding);
5291
+ const keyed = (k) => facts.filter((c) => c.kind === "config" && c.key === k && !!hostOf(c.value));
5292
+ const tokenName = token ? placeholderIn(token)?.name : void 0;
5293
+ const configs = token ? [
5294
+ .../* @__PURE__ */ new Set([
5295
+ ...keyed(token),
5296
+ ...tokenName && tokenName !== token ? keyed(tokenName) : []
5297
+ ])
5298
+ ] : call.base ? keyed(call.base) : [];
5299
+ const baseIsKey = !!call.base && facts.some((c) => c.kind === "config" && c.key === call.base);
5377
5300
  const answer = input.targets?.[r.repo]?.[call.id];
5378
5301
  if (answer) {
5379
5302
  vendor = byName2.get(factIdPart(answer));
@@ -5382,8 +5305,6 @@ function joinVendorOperations(input) {
5382
5305
  vendor = byName2.get(factIdPart(call.to));
5383
5306
  how = "named";
5384
5307
  } else {
5385
- const direct = hostOf(call.host);
5386
- const configs = call.base ? facts.filter((c) => c.kind === "config" && c.key === call.base && !!hostOf(c.value)) : [];
5387
5308
  const seen = /* @__PURE__ */ new Map();
5388
5309
  if (direct) {
5389
5310
  const v = vendorOfHost(direct);
@@ -5395,7 +5316,7 @@ function joinVendorOperations(input) {
5395
5316
  if (v && !seen.has(v.system))
5396
5317
  seen.set(v.system, { v, tie: c });
5397
5318
  }
5398
- } else {
5319
+ } else if (!token && !baseIsKey) {
5399
5320
  const b = hostOf(call.base);
5400
5321
  const v = b ? vendorOfHost(b) : void 0;
5401
5322
  if (v)
@@ -5413,49 +5334,123 @@ function joinVendorOperations(input) {
5413
5334
  continue;
5414
5335
  if (!forwarding && !takesDirect(vendor))
5415
5336
  continue;
5337
+ const own = vendor;
5338
+ const groups = /* @__PURE__ */ new Map();
5339
+ const groupOf = (path) => {
5340
+ const k = path ?? "";
5341
+ const g = groups.get(k) ?? { ...path ? { path } : {}, envs: [] };
5342
+ groups.set(k, g);
5343
+ return g;
5344
+ };
5345
+ const settings = configs.filter((c) => how !== "host" || vendorOfHost(hostOf(c.value)) === own);
5346
+ const ownPath = urlPathOf2(call.host);
5347
+ if (ownPath || !settings.length)
5348
+ groupOf(ownPath);
5349
+ for (const c of settings) {
5350
+ const g = groupOf(urlPathOf2(c.value));
5351
+ if (c.env)
5352
+ g.envs.push(c.env);
5353
+ }
5354
+ for (const g of groups.values()) {
5355
+ const env = preferredEnvironment(g.envs);
5356
+ if (env)
5357
+ g.env = env;
5358
+ g.tie = settings.find((c) => urlPathOf2(c.value) === g.path && c.env === env) ?? settings.find((c) => urlPathOf2(c.value) === g.path);
5359
+ }
5360
+ const first = preferredEnvironment([...groups.values()].flatMap((g) => g.envs));
5361
+ const lead = (g) => first !== void 0 && g.envs.includes(first) ? 0 : 1;
5362
+ const ordered = [...groups.values()].sort((a, b) => lead(a) - lead(b) || Number(!a.env) - Number(!b.env) || cmp2(a.path ?? "", b.path ?? ""));
5363
+ const several = ordered.length > 1;
5416
5364
  const name = vendor.names[0] ?? vendor.system;
5417
5365
  const method = call.method?.toUpperCase();
5418
- const what2 = [method, call.path].filter(Boolean).join(" ");
5419
- const shape = (op) => Math.max(routeScore(call.path, op.fullPath ?? op.path), op.fullPath ? routeScore(call.path, op.path) : 0);
5420
- const scored = vendor.operations.map((op) => ({ op, score: shape(op) })).filter((s) => s.score >= 400);
5421
- const fitting = scored.filter((s) => sameMethod2(method, s.op.method));
5422
- const best = Math.max(0, ...fitting.map((s) => s.score));
5423
- const hits = fitting.filter((s) => s.score === best).map((s) => s.op).sort((a, b) => cmp2(a.id, b.id));
5424
5366
  const base = {
5425
5367
  call: end(call),
5426
- ...route ? { route } : {},
5427
- ...tie ? { tie } : {},
5428
- vendor: vendor.system
5368
+ ...route ? { route } : {}
5429
5369
  };
5430
- if (hits.length === 1) {
5431
- const op = hits[0];
5432
- matches.push({
5433
- ...base,
5434
- how,
5435
- operation: op.id,
5436
- ...method || op.method ? { method: (method ?? op.method).toUpperCase() } : {},
5437
- path: call.path,
5438
- ...forwarding ? {} : { direct: true }
5370
+ const sentOf = (g) => g.path ? under(g.path, call.path) : under(void 0, call.path);
5371
+ const whatOf = (g) => [method, sentOf(g)].filter(Boolean).join(" ");
5372
+ const inEnvs = (g) => several && g.envs.length ? ` in ${[...new Set(g.envs)].sort(cmp2).join(", ")}` : "";
5373
+ const tieOf = (g) => tie && g.tie ? { tie: end(g.tie) } : tie ? { tie } : {};
5374
+ const envOf = (g) => g.env ? { env: g.env } : {};
5375
+ const results = ordered.map((g) => {
5376
+ const sent = sentOf(g);
5377
+ const shape = (op) => {
5378
+ const a = segs(sent);
5379
+ if (!a)
5380
+ return void 0;
5381
+ let bestFit;
5382
+ const served = g.path ? [op.fullPath ?? op.path] : op.fullPath ? [op.fullPath, op.path] : [op.path];
5383
+ for (const path of served) {
5384
+ const b = segs(path);
5385
+ const x = b ? fit(a, b) : void 0;
5386
+ if (x && (!bestFit || x.literals > bestFit.literals))
5387
+ bestFit = x;
5388
+ }
5389
+ return bestFit;
5390
+ };
5391
+ const scored = vendor.operations.flatMap((op) => {
5392
+ const x = shape(op);
5393
+ return x ? [{ op, ...x }] : [];
5439
5394
  });
5440
- } else if (hits.length > 1) {
5395
+ const fitting = scored.filter((x) => sameMethod2(method, x.op.method));
5396
+ const wild = fitting.some((x) => x.wildcard);
5397
+ const best = Math.max(0, ...fitting.map((x) => x.literals));
5398
+ const hits = fitting.filter((x) => wild || x.literals === best).sort((a, b) => cmp2(a.op.id, b.op.id));
5399
+ return { g, sent, scored, wild, hits };
5400
+ });
5401
+ const reached = results.filter((x) => x.hits.length === 1 || x.wild && x.hits.length > 1);
5402
+ const done = /* @__PURE__ */ new Set();
5403
+ const found = [];
5404
+ for (const x of reached)
5405
+ for (const h of x.hits) {
5406
+ if (done.has(h.op.id))
5407
+ continue;
5408
+ done.add(h.op.id);
5409
+ found.push({
5410
+ ...base,
5411
+ ...tieOf(x.g),
5412
+ vendor: vendor.system,
5413
+ how,
5414
+ operation: h.op.id,
5415
+ ...method || h.op.method ? { method: (method ?? h.op.method).toUpperCase() } : {},
5416
+ path: x.sent,
5417
+ ...envOf(x.g),
5418
+ ...x.wild ? { wildcard: true } : {},
5419
+ ...forwarding ? {} : { direct: true }
5420
+ });
5421
+ }
5422
+ matches.push(...found.sort((a, b) => cmp2(a.operation, b.operation)));
5423
+ for (const x of results.filter((y) => !y.wild && y.hits.length > 1)) {
5441
5424
  const opName = (op) => `${op.method.toUpperCase()} ${op.path}`;
5442
- const names = hits.map(opName).sort();
5425
+ const names = x.hits.map((h) => opName(h.op)).sort();
5443
5426
  asks.push({
5444
- call: end(call),
5445
- ...route ? { route } : {},
5427
+ ...base,
5446
5428
  vendor: vendor.system,
5447
- question: `Which of ${name}'s operations does ${what2}, which ${component(call)} forwards, reach: ${names.slice(0, -1).join(", ")} or ${names.at(-1)}?`,
5448
- candidates: hits.map((o) => o.id)
5429
+ question: `Which of ${name}'s operations does ${whatOf(x.g)}${inEnvs(x.g)}, which ${component(call)} forwards, reach: ${names.slice(0, -1).join(", ")} or ${names.at(-1)}?`,
5430
+ candidates: x.hits.map((h) => h.op.id),
5431
+ ...envOf(x.g)
5449
5432
  });
5450
- } else {
5451
- const others = [...new Set(scored.map((s) => s.op.method.toUpperCase()))].sort();
5433
+ }
5434
+ const missed = results.filter((x) => !x.hits.length);
5435
+ const gap = (x, what2) => {
5436
+ const others = [...new Set(x.scored.map((y) => y.op.method.toUpperCase()))].sort();
5452
5437
  gaps.push({
5453
5438
  ...base,
5439
+ ...tieOf(x.g),
5440
+ vendor: vendor.system,
5454
5441
  ...method ? { method } : {},
5455
- path: call.path,
5442
+ path: x.sent,
5443
+ ...envOf(x.g),
5456
5444
  message: `${component(call)} ${forwarding ? "forwards" : "calls"} ${what2} ${forwarding ? "to" : "on"} ${name}, whose spec publishes no such operation${others.length ? ` (it publishes ${others.join(", ")} on that path)` : ""}`
5457
5445
  });
5458
- }
5446
+ };
5447
+ if (missed.length === results.length) {
5448
+ const [head, ...rest] = missed;
5449
+ const also = rest.map((x) => `${x.sent}${inEnvs(x.g)}`);
5450
+ gap(head, `${whatOf(head.g)}${inEnvs(head.g)}${also.length ? ` (${also.join("; ")})` : ""}`);
5451
+ } else
5452
+ for (const x of missed)
5453
+ gap(x, `${whatOf(x.g)}${inEnvs(x.g)}`);
5459
5454
  }
5460
5455
  }
5461
5456
  const byCall = (x, y) => cmp2(x.call.repo, y.call.repo) || cmp2(x.call.fact, y.call.fact);
@@ -6337,7 +6332,7 @@ function callerRecords(result, repos, join18, o = {}) {
6337
6332
  } else if (known && products.length === 1 && known.kind === "GatewayRoute" && !known.product)
6338
6333
  put({ ...known, product: products[0] });
6339
6334
  for (const c of route.callers ?? []) {
6340
- const id = fit(`ag-${rc.gatewayRoute.replace(/^gw-/, "")}-${c.as}-${factIdPart(c.value)}`);
6335
+ const id = fit2(`ag-${rc.gatewayRoute.replace(/^gw-/, "")}-${c.as}-${factIdPart(c.value)}`);
6341
6336
  put({
6342
6337
  kind: "AccessGrant",
6343
6338
  schemaVersion: 2,
@@ -6387,7 +6382,7 @@ function callerRecords(result, repos, join18, o = {}) {
6387
6382
  }
6388
6383
  return [...out.values()].sort((a, b) => a.kind === b.kind ? cmp4(a.id, b.id) : cmp4(a.kind, b.kind));
6389
6384
  }
6390
- var fit = (id) => id.length <= 120 ? id : id.slice(0, 120).replace(/[-.]+$/, "");
6385
+ var fit2 = (id) => id.length <= 120 ? id : id.slice(0, 120).replace(/[-.]+$/, "");
6391
6386
  function once2(ev) {
6392
6387
  const seen = /* @__PURE__ */ new Set();
6393
6388
  return ev.filter((e) => {
@@ -6524,7 +6519,7 @@ function termGrantRecords(result, repos, o = {}) {
6524
6519
  side: "gateway",
6525
6520
  by: f.by
6526
6521
  });
6527
- const id = fit2(`ag-${g.gatewayRoute.replace(/^gw-/, "")}-${factIdPart(f.term)}-${factIdPart(f.value)}`, `${g.gatewayRoute}\0${f.term}\0${f.value}`);
6522
+ const id = fit3(`ag-${g.gatewayRoute.replace(/^gw-/, "")}-${factIdPart(f.term)}-${factIdPart(f.value)}`, `${g.gatewayRoute}\0${f.term}\0${f.value}`);
6528
6523
  out.set(id, {
6529
6524
  kind: "AccessGrant",
6530
6525
  schemaVersion: 2,
@@ -6546,7 +6541,7 @@ function termGrantRecords(result, repos, o = {}) {
6546
6541
  }
6547
6542
  return [...out.values()].sort((a, b) => cmp5(a.id, b.id));
6548
6543
  }
6549
- var fit2 = (id, whole) => id.length <= 120 ? id : `${id.slice(0, 111).replace(/[-.]+$/, "")}-${createHash3("sha256").update(whole).digest("hex").slice(0, 8)}`;
6544
+ var fit3 = (id, whole) => id.length <= 120 ? id : `${id.slice(0, 111).replace(/[-.]+$/, "")}-${createHash3("sha256").update(whole).digest("hex").slice(0, 8)}`;
6550
6545
  var ownerTermFlag = (term, value) => `term:${term}=${value}`;
6551
6546
 
6552
6547
  // packages/core/dist/facts-deps.js
@@ -8539,6 +8534,7 @@ function shuffled(list, seed) {
8539
8534
  }
8540
8535
  return out;
8541
8536
  }
8537
+ var seededShuffle = shuffled;
8542
8538
  function drawAudit(o) {
8543
8539
  return [
8544
8540
  ...shuffled(o.facts, `${o.seed}:facts`).slice(0, o.size),
@@ -8656,6 +8652,330 @@ function sampleConfirmed(audit, facts) {
8656
8652
  return new Set((audit?.items ?? []).filter((i) => i.kind === "fact" && i.answer === "right" && i.fact && auditItemHolds(i, byId)).map((i) => i.fact));
8657
8653
  }
8658
8654
 
8655
+ // packages/core/dist/canary.js
8656
+ var import_yaml10 = __toESM(require_dist(), 1);
8657
+ var canaryReportsRelOf = (root) => isAdopted(root) ? ".atticus/reports/canaries" : "reports/canaries";
8658
+ var WINDOWS_DEVICE = /^(?:con|prn|aux|nul|com[0-9]|lpt[0-9])(?:\.|$)/i;
8659
+ var isCanaryRepoName = (repo) => /^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(repo) && !repo.includes("..") && !WINDOWS_DEVICE.test(repo);
8660
+ var CANARY_READS_DIR = "atticus-reads";
8661
+ var isCanaryMetarepoId = (id) => /^[0-9a-f]{8}$/.test(id);
8662
+ var canaryRunPrefix = (repo, id) => `${repo}-${id}-`;
8663
+ var isCanaryRunName = (name, repo, id) => isCanaryRepoName(repo) && isCanaryMetarepoId(id) && name.startsWith(canaryRunPrefix(repo, id)) && /^[A-Za-z0-9]{6}$/.test(name.slice(canaryRunPrefix(repo, id).length));
8664
+ function canaryRunOf(name) {
8665
+ const m = /^(.+)-([0-9a-f]{8})-[A-Za-z0-9]{6}$/.exec(name);
8666
+ return m && isCanaryRunName(name, m[1], m[2]) ? { repo: m[1], id: m[2] } : void 0;
8667
+ }
8668
+ var CANARY_WHATS = ["entry", "call", "topic-in", "topic-out", "config"];
8669
+ var CanaryPlanted = external_exports.strictObject({
8670
+ /** `plant:<n>`, in the order planted. */
8671
+ id: external_exports.string().min(1),
8672
+ /** The fact kind a reader should write for it. */
8673
+ kind: external_exports.enum(["entry", "call", "config"]),
8674
+ what: external_exports.enum(CANARY_WHATS),
8675
+ /** The template's stack, as `@maycombhq/verify` names it. */
8676
+ stack: external_exports.string().min(1),
8677
+ /** Where it was planted, repo-relative, and the line that holds it. */
8678
+ file: external_exports.string().min(1),
8679
+ line: external_exports.number().int().positive(),
8680
+ /** What it says, in one line (synthetic: no code of the repo). */
8681
+ claim: external_exports.string().min(1),
8682
+ /**
8683
+ * Its own words, folded (`foldCanary`): a fact of its kind whose claim holds them is about it.
8684
+ * Drawn so that no fact of the repo holds them.
8685
+ */
8686
+ needle: external_exports.string().min(1)
8687
+ });
8688
+ var CanaryRemoved = external_exports.strictObject({
8689
+ /** `remove:<fact id>`. */
8690
+ id: external_exports.string().min(1),
8691
+ /** The verified fact whose cited line was commented out. */
8692
+ fact: external_exports.string().min(1),
8693
+ kind: external_exports.string().min(1),
8694
+ file: external_exports.string().min(1),
8695
+ line: external_exports.number().int().positive(),
8696
+ /** The fact's claim, as the facts already state it. */
8697
+ claim: external_exports.string().min(1),
8698
+ /** The fact's cited value: a fact of the kind citing that very line with it is the removed one. */
8699
+ value: external_exports.string().min(1),
8700
+ /**
8701
+ * What the fact claims (`canaryNeedleOf`): an entry's or call's method and path with its
8702
+ * parameters left out (`get /ledger-v1-transfers`), a config key exactly, folded. A fact of the
8703
+ * kind with the same needle claims the removed one.
8704
+ */
8705
+ needle: external_exports.string().min(1),
8706
+ how: external_exports.literal("commented")
8707
+ });
8708
+ var CanarySkipped = external_exports.strictObject({
8709
+ stack: external_exports.string().min(1),
8710
+ what: external_exports.enum(CANARY_WHATS),
8711
+ reason: external_exports.string().min(1)
8712
+ });
8713
+ var CanaryKey = external_exports.strictObject({
8714
+ schema: external_exports.literal(1),
8715
+ repo: external_exports.string().refine(isCanaryRepoName, "not a repo name"),
8716
+ seed: external_exports.string().min(1),
8717
+ commit: external_exports.string().optional(),
8718
+ /** The run folder's base name: the copy (`<repo>/`), `prompt.md` and `facts.jsonl` are in it. */
8719
+ run: external_exports.string().min(1),
8720
+ /**
8721
+ * The real path of the `atticus-reads` folder the run folder is in (third review of ADR 0196),
8722
+ * so a temporary folder set otherwise later still finds it; checked again (named so, a real
8723
+ * folder by its real path, this user's, closed to others) before it is used. A key planted
8724
+ * before has none: its run is in the temporary folder's.
8725
+ */
8726
+ reads: external_exports.string().min(1).optional(),
8727
+ stacks: external_exports.array(external_exports.string()),
8728
+ planted: external_exports.array(CanaryPlanted),
8729
+ removed: external_exports.array(CanaryRemoved),
8730
+ skipped: external_exports.array(CanarySkipped).default([]),
8731
+ at: external_exports.string()
8732
+ }).refine((k) => canaryRunOf(k.run)?.repo === k.repo, {
8733
+ message: "run is not this repo's run folder name",
8734
+ path: ["run"]
8735
+ });
8736
+ var CanaryRate = external_exports.strictObject({
8737
+ k: external_exports.number().int().nonnegative(),
8738
+ n: external_exports.number().int().nonnegative(),
8739
+ rate: external_exports.number().nullable(),
8740
+ low: external_exports.number().nullable(),
8741
+ high: external_exports.number().nullable()
8742
+ });
8743
+ var CanaryReport = external_exports.strictObject({
8744
+ schema: external_exports.literal(1),
8745
+ repo: external_exports.string().min(1),
8746
+ commit: external_exports.string().optional(),
8747
+ /** The seed it was planted by: drawn at random unless one was given, so no read can guess it. */
8748
+ seed: external_exports.string().min(1),
8749
+ /** When it was scored, and who scored it. */
8750
+ at: external_exports.string(),
8751
+ by: external_exports.string().min(1),
8752
+ stacks: external_exports.array(external_exports.string()),
8753
+ /** The facts the read wrote, those the verifier kept and rejected, and lines that didn't read. */
8754
+ read: external_exports.strictObject({
8755
+ facts: external_exports.number().int().nonnegative(),
8756
+ kept: external_exports.number().int().nonnegative(),
8757
+ rejected: external_exports.number().int().nonnegative(),
8758
+ unread: external_exports.number().int().nonnegative().default(0)
8759
+ }),
8760
+ /**
8761
+ * Each planted item by an opaque id, what it stood for, its stack and how the read did: never
8762
+ * its words, file or line (review of ADR 0196), so a committed report teaches no read what a
8763
+ * canary plants.
8764
+ */
8765
+ planted: external_exports.array(CanaryPlanted.pick({ id: true, kind: true, what: true, stack: true }).extend({
8766
+ /** found: a kept fact; rejected: only a fact the verifier refused; missed: none. */
8767
+ result: external_exports.enum(["found", "rejected", "missed"])
8768
+ })),
8769
+ /** The items the templates have that this repo couldn't serve, so weren't planted. */
8770
+ skipped: external_exports.array(CanarySkipped).default([]),
8771
+ removed: external_exports.array(CanaryRemoved.omit({ needle: true }).extend({
8772
+ /**
8773
+ * absent: no fact claims it; kept: a kept fact cites its line or one beside it, by its cite
8774
+ * or a part (silent); rejected: one did, refused; elsewhere: a fact names its path or key
8775
+ * but cites neither its line nor one beside it, so may be about another line (in no rate).
8776
+ */
8777
+ result: external_exports.enum(["absent", "kept", "rejected", "elsewhere"]),
8778
+ by: external_exports.string().optional()
8779
+ })),
8780
+ /** Planted found by a kept fact, of planted. */
8781
+ recall: CanaryRate,
8782
+ /** Removed the read still claimed at its line, kept by the verifier or not: the reader's rate. */
8783
+ fabrication: CanaryRate,
8784
+ /** Removed still claimed at its line by a fact the verifier kept: backed, and wrong (silent). */
8785
+ passed: CanaryRate
8786
+ });
8787
+ function parseCanaryReport(text4) {
8788
+ let raw;
8789
+ try {
8790
+ raw = (0, import_yaml10.parse)(text4);
8791
+ } catch (e) {
8792
+ return { ok: false, issues: [`not YAML: ${e.message.split("\n")[0]}`] };
8793
+ }
8794
+ const r = CanaryReport.safeParse(raw);
8795
+ if (!r.success)
8796
+ return {
8797
+ ok: false,
8798
+ issues: r.error.issues.map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`)
8799
+ };
8800
+ return { ok: true, report: r.data };
8801
+ }
8802
+ var serializeCanaryReport = (r) => (0, import_yaml10.stringify)(CanaryReport.parse(r), { lineWidth: 0 });
8803
+ var foldCanary = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
8804
+ function canaryClaimText(f) {
8805
+ const x = f;
8806
+ return ["path", "key", "name", "topic", "source", "base"].map((k) => typeof x[k] === "string" ? x[k] : "").concat(f.cite.value).map(foldCanary).filter(Boolean).join(" ");
8807
+ }
8808
+ var pathKey = (p2) => foldCanary(p2.replace(/\{[^}]*\}|:[A-Za-z_]\w*/g, "-param-"));
8809
+ function canaryNeedleOf(f) {
8810
+ const x = f;
8811
+ if ((f.kind === "entry" || f.kind === "call") && typeof x.path === "string" && pathKey(x.path))
8812
+ return withMethod(x.method, pathKey(x.path));
8813
+ if (f.kind === "config" && typeof x.key === "string" && foldCanary(x.key))
8814
+ return foldCanary(x.key);
8815
+ return foldCanary(f.cite.value) || f.cite.value;
8816
+ }
8817
+ var withMethod = (method, path) => typeof method === "string" && foldCanary(method) ? `${foldCanary(method)} ${path}` : path;
8818
+ var anyMethod = (m) => m === void 0 || m === "any" || m === "all";
8819
+ function sameNeedle(a, b) {
8820
+ const [am, ap] = a.includes(" ") ? a.split(" ") : [void 0, a];
8821
+ const [bm, bp] = b.includes(" ") ? b.split(" ") : [void 0, b];
8822
+ return ap === bp && (anyMethod(am) || anyMethod(bm) || am === bm);
8823
+ }
8824
+ var plantedBy = (p2, f) => f.kind === p2.kind && canaryClaimText(f).includes(p2.needle);
8825
+ var citesNear = (f, file, line) => [f.cite, ...f.cite.with ?? []].some((c) => c.file === file && Math.abs(c.line - line) <= 1);
8826
+ function removedMatch(r, f) {
8827
+ if (f.kind !== r.kind)
8828
+ return void 0;
8829
+ const same = sameNeedle(canaryNeedleOf(f), r.needle);
8830
+ const near = citesNear(f, r.file, r.line);
8831
+ if (near && same)
8832
+ return "near";
8833
+ const v = foldCanary(r.value);
8834
+ if (near && v && ([f.cite, ...f.cite.with ?? []].some((c) => c.file === r.file && c.line === r.line && foldCanary(c.value) === v) || (f.kind === "entry" || f.kind === "call") && /^\//.test(r.value.trim()) && sameNeedle(canaryNeedleOf(f), withMethod(r.needle.includes(" ") ? r.needle.split(" ")[0] : void 0, pathKey(r.value)))))
8835
+ return "value";
8836
+ return same ? "elsewhere" : void 0;
8837
+ }
8838
+ function removedBy(r, f) {
8839
+ const m = removedMatch(r, f);
8840
+ return m === "value" ? "near" : m;
8841
+ }
8842
+ function canaryRate(k, n) {
8843
+ const ci = wilson(k, n);
8844
+ return {
8845
+ k,
8846
+ n,
8847
+ rate: n ? Math.round(k / n * 1e3) / 1e3 : null,
8848
+ low: ci?.low ?? null,
8849
+ high: ci?.high ?? null
8850
+ };
8851
+ }
8852
+ function scoreCanary(key3, read, o) {
8853
+ const taken = /* @__PURE__ */ new Set();
8854
+ const first = (list, ok) => {
8855
+ const f = list.find((x) => !taken.has(x) && ok(x));
8856
+ if (f)
8857
+ taken.add(f);
8858
+ return f;
8859
+ };
8860
+ const planted = key3.planted.map((p2) => {
8861
+ const kept = first(read.kept, (f) => plantedBy(p2, f));
8862
+ const refused = kept ? void 0 : first(read.rejected, (f) => plantedBy(p2, f));
8863
+ return {
8864
+ id: p2.id,
8865
+ kind: p2.kind,
8866
+ what: p2.what,
8867
+ stack: p2.stack,
8868
+ result: kept ? "found" : refused ? "rejected" : "missed"
8869
+ };
8870
+ });
8871
+ const got = /* @__PURE__ */ new Map();
8872
+ const passes = [
8873
+ [read.kept, "near", "kept"],
8874
+ [read.rejected, "near", "rejected"],
8875
+ [read.kept, "value", "kept"],
8876
+ [read.rejected, "value", "rejected"],
8877
+ [[...read.kept, ...read.rejected], "elsewhere", "elsewhere"]
8878
+ ];
8879
+ for (const [list, m, result] of passes)
8880
+ for (const r of key3.removed) {
8881
+ if (got.has(r.id))
8882
+ continue;
8883
+ const f = first(list, (x) => removedMatch(r, x) === m);
8884
+ if (f)
8885
+ got.set(r.id, { result, by: f });
8886
+ }
8887
+ const removed = key3.removed.map((r) => {
8888
+ const g = got.get(r.id);
8889
+ return {
8890
+ ...(({ needle: _n, ...rest }) => rest)(r),
8891
+ result: g?.result ?? "absent",
8892
+ ...g ? { by: g.by.id } : {}
8893
+ };
8894
+ });
8895
+ const counted = removed.filter((r) => r.result !== "elsewhere");
8896
+ return {
8897
+ schema: 1,
8898
+ repo: key3.repo,
8899
+ ...key3.commit ? { commit: key3.commit } : {},
8900
+ seed: key3.seed,
8901
+ at: o.at,
8902
+ by: o.by,
8903
+ stacks: [...key3.stacks],
8904
+ read: {
8905
+ facts: read.kept.length + read.rejected.length,
8906
+ kept: read.kept.length,
8907
+ rejected: read.rejected.length,
8908
+ unread: read.unread ?? 0
8909
+ },
8910
+ planted,
8911
+ skipped: [...key3.skipped ?? []],
8912
+ removed,
8913
+ recall: canaryRate(planted.filter((p2) => p2.result === "found").length, planted.length),
8914
+ fabrication: canaryRate(counted.filter((r) => r.result === "kept" || r.result === "rejected").length, counted.length),
8915
+ passed: canaryRate(counted.filter((r) => r.result === "kept").length, counted.length)
8916
+ };
8917
+ }
8918
+ var GUESSED = /* @__PURE__ */ new Set([
8919
+ ...JOIN_GUESS_FLAGS,
8920
+ JOINED_BY_PATH_OVERLAP,
8921
+ JOINED_BY_AI
8922
+ ]);
8923
+ var GUESSED_JOINS = { test: (how) => GUESSED.has(how) };
8924
+ var answered = (t) => t.right + t.wrong;
8925
+ function canaryCovers(reports) {
8926
+ const by = /* @__PURE__ */ new Map();
8927
+ for (const r of reports)
8928
+ for (const p2 of r.planted)
8929
+ by.set(p2.stack, (by.get(p2.stack) ?? /* @__PURE__ */ new Set()).add(p2.what));
8930
+ return [...by.keys()].sort().map((stack) => ({ stack, what: CANARY_WHATS.filter((w) => by.get(stack).has(w)) }));
8931
+ }
8932
+ function silentErrorRate(audit, canaries) {
8933
+ let wrong = 0;
8934
+ let backed = 0;
8935
+ if (audit) {
8936
+ const p2 = audit.precision;
8937
+ const links = Object.entries(p2.byHow).filter(([how]) => !GUESSED_JOINS.test(how));
8938
+ wrong += p2.facts.wrong + links.reduce((n, [, t]) => n + t.wrong, 0);
8939
+ backed += answered(p2.facts) + links.reduce((n, [, t]) => n + answered(t), 0);
8940
+ }
8941
+ let found = 0;
8942
+ let planted = 0;
8943
+ let kept = 0;
8944
+ let claimed = 0;
8945
+ let removed = 0;
8946
+ let caught = 0;
8947
+ let elsewhere = 0;
8948
+ for (const c of canaries) {
8949
+ found += c.recall.k;
8950
+ planted += c.recall.n;
8951
+ kept += c.passed.k;
8952
+ claimed += c.fabrication.k;
8953
+ removed += c.passed.n;
8954
+ caught += c.removed.filter((r) => r.result === "rejected").length;
8955
+ elsewhere += c.removed.filter((r) => r.result === "elsewhere").length;
8956
+ }
8957
+ return {
8958
+ misread: canaryRate(wrong, backed),
8959
+ passed: canaryRate(kept, removed),
8960
+ recall: canaryRate(found, planted),
8961
+ fabrication: canaryRate(claimed, removed),
8962
+ caught,
8963
+ elsewhere,
8964
+ repos: { audited: audit?.repos ?? 0, canaries: canaries.length },
8965
+ covers: canaryCovers(canaries)
8966
+ };
8967
+ }
8968
+ function latestCanaries(reports) {
8969
+ const by = /* @__PURE__ */ new Map();
8970
+ for (const r of reports) {
8971
+ const had = by.get(r.repo);
8972
+ if (!had || had.at < r.at)
8973
+ by.set(r.repo, r);
8974
+ }
8975
+ return [...by.values()].sort((a, b) => a.repo < b.repo ? -1 : a.repo > b.repo ? 1 : 0);
8976
+ }
8977
+ var isWindowsDeviceName = (name) => WINDOWS_DEVICE.test(name);
8978
+
8659
8979
  // packages/core/dist/stack-helpers.js
8660
8980
  var STACK_HELPERS = [
8661
8981
  "framework-models",
@@ -9086,6 +9406,7 @@ __export(api_exports, {
9086
9406
  AnsweredQuestion: () => AnsweredQuestion,
9087
9407
  ArchiveRequest: () => ArchiveRequest,
9088
9408
  ArtifactContent: () => ArtifactContent,
9409
+ ArtifactFiles: () => ArtifactFiles,
9089
9410
  ArtifactStatus: () => ArtifactStatus,
9090
9411
  AttachFileRequest: () => AttachFileRequest,
9091
9412
  AttachPastChangeRequest: () => AttachPastChangeRequest,
@@ -9099,12 +9420,31 @@ __export(api_exports, {
9099
9420
  BaselineRequest: () => BaselineRequest,
9100
9421
  BoxCorrections: () => BoxCorrections,
9101
9422
  BranchCompare: () => BranchCompare,
9423
+ BuildHandEdit: () => BuildHandEdit,
9424
+ BuildRefusalView: () => BuildRefusalView,
9425
+ BuildRemoval: () => BuildRemoval,
9426
+ BuildRemovalInput: () => BuildRemovalInput,
9427
+ BuildReportFile: () => BuildReportFile,
9428
+ BuildReportView: () => BuildReportView,
9429
+ BuildSourceView: () => BuildSourceView,
9102
9430
  CHANGE_OWNER_ROLES: () => CHANGE_OWNER_ROLES,
9103
9431
  CONFIRMED_WRITES: () => CONFIRMED_WRITES,
9432
+ CanaryRateView: () => CanaryRateView,
9433
+ CanaryRepoView: () => CanaryRepoView,
9434
+ CanaryView: () => CanaryView,
9104
9435
  CandidateApiView: () => CandidateApiView,
9105
9436
  CandidateCallView: () => CandidateCallView,
9106
9437
  CandidateSuggestion: () => CandidateSuggestion,
9438
+ CatalogBuildRequest: () => CatalogBuildRequest,
9439
+ CatalogBuildView: () => CatalogBuildView,
9440
+ CatalogEditsRequest: () => CatalogEditsRequest,
9441
+ CatalogPruneRequest: () => CatalogPruneRequest,
9442
+ CatalogPruneView: () => CatalogPruneView,
9107
9443
  CatalogRecord: () => CatalogRecord2,
9444
+ CatalogUndoRequest: () => CatalogUndoRequest,
9445
+ CatalogUndoView: () => CatalogUndoView,
9446
+ CatalogUpgradeRequest: () => CatalogUpgradeRequest,
9447
+ CatalogUpgradeView: () => CatalogUpgradeView,
9108
9448
  ChangeCockpit: () => ChangeCockpit,
9109
9449
  ChangeConformance: () => ChangeConformance,
9110
9450
  ChangeDetail: () => ChangeDetail,
@@ -9117,6 +9457,7 @@ __export(api_exports, {
9117
9457
  ChangeMap: () => ChangeMap,
9118
9458
  ChangeNeedsView: () => ChangeNeedsView,
9119
9459
  ChangeOwnersRequest: () => ChangeOwnersRequest,
9460
+ ChangeProblems: () => ChangeProblems,
9120
9461
  ChangePrototype: () => ChangePrototype,
9121
9462
  ChangePrototypeList: () => ChangePrototypeList,
9122
9463
  ChangeState: () => ChangeState,
@@ -9158,6 +9499,14 @@ __export(api_exports, {
9158
9499
  CorrectionView: () => CorrectionView,
9159
9500
  Coverage: () => Coverage,
9160
9501
  CreateMetarepoRequest: () => CreateMetarepoRequest,
9502
+ CrossCheckCite: () => CrossCheckCite,
9503
+ CrossCheckCounts: () => CrossCheckCounts,
9504
+ CrossCheckDismissRequest: () => CrossCheckDismissRequest,
9505
+ CrossCheckItem: () => CrossCheckItem,
9506
+ CrossCheckPromoteRequest: () => CrossCheckPromoteRequest,
9507
+ CrossCheckPromoteView: () => CrossCheckPromoteView,
9508
+ CrossCheckSide: () => CrossCheckSide,
9509
+ CrossCheckView: () => CrossCheckView,
9161
9510
  DEFAULT_PORT: () => DEFAULT_PORT,
9162
9511
  DRAFT_PAGES: () => DRAFT_PAGES,
9163
9512
  DecideStateView: () => DecideStateView,
@@ -9181,6 +9530,7 @@ __export(api_exports, {
9181
9530
  FactCiteView: () => FactCiteView,
9182
9531
  FactCorrectionRequest: () => FactCorrectionRequest,
9183
9532
  FactCorrectionResult: () => FactCorrectionResult,
9533
+ FactsApplyRequest: () => FactsApplyRequest,
9184
9534
  FileChangeResult: () => FileChangeResult,
9185
9535
  FileEditView: () => FileEditView,
9186
9536
  FillRequestFieldsRequest: () => FillRequestFieldsRequest,
@@ -9308,6 +9658,8 @@ __export(api_exports, {
9308
9658
  RepoAbout: () => RepoAbout,
9309
9659
  RepoBranchesList: () => RepoBranchesList,
9310
9660
  RepoBranchesView: () => RepoBranchesView,
9661
+ RepoCrossCheck: () => RepoCrossCheck,
9662
+ RepoFactsBatch: () => RepoFactsBatch,
9311
9663
  RepoFactsView: () => RepoFactsView,
9312
9664
  RepoOwnerView: () => RepoOwnerView,
9313
9665
  RepoTypeDetectView: () => RepoTypeDetectView,
@@ -9396,6 +9748,7 @@ __export(api_exports, {
9396
9748
  TrustView: () => TrustView,
9397
9749
  UndeclareLinkRequest: () => UndeclareLinkRequest,
9398
9750
  UndoBatchResult: () => UndoBatchResult,
9751
+ UndoCopyView: () => UndoCopyView,
9399
9752
  UndoCorrectionRequest: () => UndoCorrectionRequest,
9400
9753
  UpgradeView: () => UpgradeView,
9401
9754
  UpstreamRequest: () => UpstreamRequest,
@@ -9410,7 +9763,7 @@ __export(api_exports, {
9410
9763
  WorkItemSyncResult: () => WorkItemSyncResult,
9411
9764
  openApiDocument: () => openApiDocument
9412
9765
  });
9413
- var API_VERSION = "3.11.0";
9766
+ var API_VERSION = "3.12.0";
9414
9767
  var DEFAULT_PORT = 4321;
9415
9768
  var NextStep = external_exports.object({ step: external_exports.literal("sync"), repos: external_exports.array(external_exports.string()) });
9416
9769
  var Problem = external_exports.object({
@@ -9428,7 +9781,12 @@ var Problem = external_exports.object({
9428
9781
  * 3.11.0 (beta.25): for a 500 that wrote only part of what was asked, the files left written
9429
9782
  * (each in the metarepo, or in `repo`'s working copy), so the app reads them again.
9430
9783
  */
9431
- written: external_exports.array(external_exports.object({ repo: external_exports.string().optional(), file: external_exports.string() })).optional()
9784
+ written: external_exports.array(external_exports.object({ repo: external_exports.string().optional(), file: external_exports.string() })).optional(),
9785
+ /**
9786
+ * 3.12.0 (beta.27): which refusal it is, where one status has more than one the app tells
9787
+ * apart (an owner question's send: 409 `being-sent` or `already-sent`).
9788
+ */
9789
+ code: external_exports.string().optional()
9432
9790
  });
9433
9791
  var Kind = external_exports.enum(RECORD_KINDS);
9434
9792
  var CatalogRecord2 = external_exports.union(RECORD_KINDS.map((k) => RECORD_SCHEMAS[k]));
@@ -9717,7 +10075,9 @@ var Job = external_exports.object({
9717
10075
  finishedAt: external_exports.string().optional(),
9718
10076
  errors: external_exports.array(external_exports.string()),
9719
10077
  /** Kind-specific outcome, e.g. scan diff counts. */
9720
- result: external_exports.record(external_exports.string(), external_exports.unknown()).optional()
10078
+ result: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
10079
+ /** 3.12.0: Stop was asked and the job is ending (it stops at its next safe point). */
10080
+ stopping: external_exports.boolean().optional()
9721
10081
  });
9722
10082
  var JobAccepted = external_exports.object({ jobId: external_exports.string() });
9723
10083
  var ArtifactStatus = external_exports.object({
@@ -9791,6 +10151,15 @@ var ArtifactContent = external_exports.object({
9791
10151
  /** sha256 of the content; send it back on save to detect concurrent edits. */
9792
10152
  sha256: external_exports.string()
9793
10153
  });
10154
+ var ArtifactFiles = external_exports.object({
10155
+ /** By the file asked for (`file`), in the order asked. */
10156
+ files: external_exports.array(ArtifactContent.extend({ file: external_exports.string() })),
10157
+ /**
10158
+ * Beta.27 re-review: by file, the problem its one-file read would have answered (a story
10159
+ * deleted since the page listed it): the call answers the others, never fails whole.
10160
+ */
10161
+ problems: external_exports.record(external_exports.string(), external_exports.object({ status: external_exports.number().int(), title: external_exports.string(), detail: external_exports.string().optional() })).optional()
10162
+ });
9794
10163
  var Task = external_exports.object({
9795
10164
  id: external_exports.string(),
9796
10165
  repo: RecordId,
@@ -10241,6 +10610,293 @@ var AnswerBoxResult = external_exports.object({
10241
10610
  */
10242
10611
  stamp: external_exports.string().optional()
10243
10612
  });
10613
+ var CrossCheckCite = external_exports.object({
10614
+ file: external_exports.string(),
10615
+ line: external_exports.number().int().optional(),
10616
+ commit: external_exports.string().optional()
10617
+ });
10618
+ var CrossCheckSide = external_exports.object({
10619
+ id: external_exports.string(),
10620
+ value: external_exports.unknown(),
10621
+ cites: external_exports.array(CrossCheckCite)
10622
+ });
10623
+ var CrossCheckItem = external_exports.object({
10624
+ key: external_exports.string(),
10625
+ kind: external_exports.string(),
10626
+ state: external_exports.enum(["agree", "readers-only", "facts-only", "disagree"]),
10627
+ readers: CrossCheckSide.optional(),
10628
+ facts: CrossCheckSide.optional(),
10629
+ fields: external_exports.array(external_exports.object({ field: external_exports.string(), readers: external_exports.unknown(), facts: external_exports.unknown() })).optional(),
10630
+ dismissed: external_exports.literal(true).optional(),
10631
+ /**
10632
+ * The SHA-256 of the readers' value as shown (its JSON), for a readers-only or disagreeing
10633
+ * item: a dismissal sends it back, so it dismisses the value the page showed (409 when the
10634
+ * readers say another now). Only GET /api/crosscheck/{repo} says it.
10635
+ */
10636
+ readersSha256: external_exports.string().optional(),
10637
+ /**
10638
+ * A readers-only item a person promoted to assert: the `by: person` fact in the repo's facts
10639
+ * file and where it stands: `written` (not verified yet), `verified` (the verifier found it on
10640
+ * its line; `atticus verify <repo> --write` puts it in the catalog) or `rejected` (with why, in
10641
+ * facts/<repo>.rejected.jsonl). Only GET /api/crosscheck/{repo} says it.
10642
+ */
10643
+ promoted: external_exports.object({
10644
+ fact: external_exports.string(),
10645
+ state: external_exports.enum(["written", "verified", "rejected"]),
10646
+ file: external_exports.string(),
10647
+ line: external_exports.number().int(),
10648
+ message: external_exports.string().optional()
10649
+ }).optional()
10650
+ });
10651
+ var CrossCheckCounts = external_exports.object({
10652
+ agree: external_exports.number().int(),
10653
+ readersOnly: external_exports.number().int(),
10654
+ factsOnly: external_exports.number().int(),
10655
+ disagree: external_exports.number().int(),
10656
+ dismissed: external_exports.number().int()
10657
+ });
10658
+ var RepoCrossCheck = external_exports.object({
10659
+ repo: external_exports.string(),
10660
+ state: external_exports.enum(["compared", "no-facts", "no-readers", "legacy", "unusable"]),
10661
+ readersCommit: external_exports.string().optional(),
10662
+ factsCommit: external_exports.string().optional(),
10663
+ readersSlot: external_exports.string().optional(),
10664
+ factsSlot: external_exports.string().optional(),
10665
+ dismissals: external_exports.string(),
10666
+ counts: CrossCheckCounts,
10667
+ /** Every item but those that agree (GET /api/crosscheck lists none: each repo's own call does). */
10668
+ items: external_exports.array(CrossCheckItem),
10669
+ problem: external_exports.string().optional(),
10670
+ /** The base clone's commit, when it is there: a slot behind it is shown as read at its commit. */
10671
+ head: external_exports.string().optional()
10672
+ });
10673
+ var CrossCheckView = external_exports.object({
10674
+ repos: external_exports.array(RepoCrossCheck),
10675
+ problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
10676
+ });
10677
+ var CrossCheckDismissRequest = external_exports.strictObject({
10678
+ key: external_exports.string().trim().min(1).max(500),
10679
+ undo: external_exports.literal(true).optional(),
10680
+ /** The item's `readersSha256` as the page showed it: required to dismiss (not to list again). */
10681
+ sha256: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
10682
+ });
10683
+ var CrossCheckPromoteView = external_exports.object({
10684
+ repo: external_exports.string(),
10685
+ key: external_exports.string(),
10686
+ can: external_exports.boolean(),
10687
+ why: external_exports.string().optional(),
10688
+ factsFile: external_exports.string(),
10689
+ fact: external_exports.string().optional(),
10690
+ factKind: external_exports.string().optional(),
10691
+ line: external_exports.string().optional(),
10692
+ sha256: external_exports.string().optional(),
10693
+ cite: external_exports.object({
10694
+ file: external_exports.string(),
10695
+ line: external_exports.number().int(),
10696
+ value: external_exports.string(),
10697
+ text: external_exports.string().optional(),
10698
+ commit: external_exports.string()
10699
+ }).optional(),
10700
+ fromSnapshot: external_exports.boolean().optional(),
10701
+ already: external_exports.boolean().optional()
10702
+ });
10703
+ var CrossCheckPromoteRequest = external_exports.strictObject({
10704
+ key: external_exports.string().trim().min(1).max(500),
10705
+ sha256: external_exports.string().regex(/^[0-9a-f]{64}$/)
10706
+ });
10707
+ var BuildRemovalInput = external_exports.object({
10708
+ what: external_exports.enum([
10709
+ "answers",
10710
+ "pairings",
10711
+ "org-pack",
10712
+ "curated",
10713
+ "traffic",
10714
+ "shared",
10715
+ "inputs",
10716
+ "proposals",
10717
+ "federated",
10718
+ "other"
10719
+ ]),
10720
+ path: external_exports.string()
10721
+ });
10722
+ var BuildRemoval = external_exports.object({
10723
+ path: external_exports.string(),
10724
+ kind: external_exports.string(),
10725
+ id: external_exports.string(),
10726
+ repos: external_exports.array(external_exports.string()),
10727
+ explainedBy: external_exports.array(external_exports.string()),
10728
+ /** What kind of change explains it: a slot, the manifests, archived, curated, an input, the build. */
10729
+ reasons: external_exports.array(external_exports.enum(["slot", "manifest", "archived", "curated", "input", "build"])).optional(),
10730
+ /** The inputs other than a slot that changed and explain it (an answer, say), when any did. */
10731
+ inputs: external_exports.array(BuildRemovalInput).optional()
10732
+ });
10733
+ var BuildHandEdit = external_exports.object({
10734
+ path: external_exports.string(),
10735
+ how: external_exports.enum(["changed", "added", "deleted"])
10736
+ });
10737
+ var BuildRefusalView = external_exports.object({
10738
+ reasons: external_exports.array(external_exports.enum([
10739
+ "nothing-read",
10740
+ "empty",
10741
+ "unexplained-removals",
10742
+ "large-removals",
10743
+ "hand-edits",
10744
+ "not-upgraded"
10745
+ ])),
10746
+ message: external_exports.string(),
10747
+ removals: external_exports.array(BuildRemoval).optional(),
10748
+ unexplained: external_exports.array(BuildRemoval).optional(),
10749
+ allowRemovals: external_exports.number().int().optional(),
10750
+ edits: external_exports.array(BuildHandEdit).optional(),
10751
+ discardEdits: external_exports.number().int().optional(),
10752
+ /** A scan that read nothing: each repo it couldn't read in full, and why. */
10753
+ unread: external_exports.array(external_exports.object({ repo: external_exports.string(), why: external_exports.string() })).optional(),
10754
+ /** What goes on in a terminal (the build, the hand edits' curate, or the upgrade). */
10755
+ command: external_exports.string(),
10756
+ /**
10757
+ * The hash of what the lists say (each removal's path, reasons and words; each hand edit's
10758
+ * path and how), as GET /api/build's `pending.plan` hashes them: a confirm of this refusal
10759
+ * sends it back (POST /api/facts/{repo}/apply, POST /api/scan), and a list that changed
10760
+ * meanwhile writes nothing.
10761
+ */
10762
+ plan: external_exports.string().optional()
10763
+ });
10764
+ var BuildReportFile = external_exports.object({ path: external_exports.string(), kind: external_exports.string(), id: external_exports.string() });
10765
+ var BuildReportView = external_exports.object({
10766
+ command: external_exports.string(),
10767
+ at: external_exports.string(),
10768
+ generated: external_exports.string(),
10769
+ outcome: external_exports.enum(["written", "unchanged", "refused", "stopped"]),
10770
+ refused: BuildRefusalView.optional(),
10771
+ stopped: external_exports.string().optional(),
10772
+ run: external_exports.array(external_exports.string()),
10773
+ counts: external_exports.object({
10774
+ records: external_exports.number().int(),
10775
+ added: external_exports.number().int(),
10776
+ changed: external_exports.number().int(),
10777
+ removed: external_exports.number().int(),
10778
+ written: external_exports.number().int(),
10779
+ unchanged: external_exports.number().int()
10780
+ }),
10781
+ added: external_exports.array(BuildReportFile),
10782
+ changed: external_exports.array(BuildReportFile),
10783
+ /** Every removal with why: for a refusal, those it would have made, unexplained ones included. */
10784
+ removed: external_exports.array(BuildRemoval),
10785
+ slots: external_exports.array(external_exports.string()),
10786
+ /** The undo copy a written build took. */
10787
+ undo: external_exports.number().int().optional(),
10788
+ discarded: external_exports.array(BuildHandEdit).optional()
10789
+ });
10790
+ var BuildSourceView = external_exports.object({
10791
+ repo: external_exports.string(),
10792
+ source: external_exports.enum(["facts", "readers", "legacy", "none"]),
10793
+ commit: external_exports.string().optional(),
10794
+ slot: external_exports.string().optional(),
10795
+ problem: external_exports.string().optional()
10796
+ });
10797
+ var CatalogBuildView = external_exports.object({
10798
+ sources: external_exports.array(BuildSourceView),
10799
+ pending: external_exports.object({
10800
+ upToDate: external_exports.boolean(),
10801
+ removals: external_exports.array(BuildRemoval),
10802
+ refused: BuildRefusalView.optional(),
10803
+ /**
10804
+ * A hash of what the lists say (each removal's path, reasons and words; each hand edit's path
10805
+ * and how), which a confirm of them sends back (POST /api/build, POST
10806
+ * /api/build/edits/curate): a list that changed meanwhile is a 409 and nothing runs.
10807
+ */
10808
+ plan: external_exports.string()
10809
+ }),
10810
+ last: BuildReportView.optional(),
10811
+ upgrade: external_exports.literal(true).optional(),
10812
+ orphaned: external_exports.array(external_exports.object({
10813
+ repo: external_exports.string(),
10814
+ why: external_exports.enum(["not-listed", "archived"]),
10815
+ files: external_exports.array(external_exports.string())
10816
+ })),
10817
+ problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
10818
+ });
10819
+ var CatalogBuildRequest = external_exports.strictObject({
10820
+ allowRemovals: external_exports.number().int().min(0).max(1e6).optional(),
10821
+ discardEdits: external_exports.number().int().min(0).max(1e6).optional(),
10822
+ /** GET /api/build's `pending.plan`: required with a count (the list it confirms). */
10823
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
10824
+ });
10825
+ var CatalogEditsRequest = external_exports.strictObject({
10826
+ count: external_exports.number().int().min(1).max(1e6),
10827
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/)
10828
+ });
10829
+ var UndoCopyView = external_exports.object({
10830
+ /** 1 is the latest build, up to 5. */
10831
+ n: external_exports.number().int(),
10832
+ command: external_exports.string(),
10833
+ at: external_exports.string(),
10834
+ commit: external_exports.string().nullable(),
10835
+ files: external_exports.number().int()
10836
+ });
10837
+ var CatalogUndoView = external_exports.object({
10838
+ copies: external_exports.array(UndoCopyView),
10839
+ plan: external_exports.object({
10840
+ n: external_exports.number().int(),
10841
+ takesBack: external_exports.array(external_exports.object({ n: external_exports.number().int(), command: external_exports.string() })),
10842
+ files: external_exports.array(external_exports.object({ path: external_exports.string(), to: external_exports.enum(["file", "absent"]) })),
10843
+ /** A hash of the undo copies it takes back (their folder numbers) and each file, sent back by the confirm. */
10844
+ hash: external_exports.string()
10845
+ }).optional(),
10846
+ /** Why there is nothing to undo, in words. */
10847
+ problem: external_exports.string().optional()
10848
+ });
10849
+ var CatalogUndoRequest = external_exports.strictObject({
10850
+ n: external_exports.number().int().min(1).max(5),
10851
+ files: external_exports.number().int().min(0),
10852
+ /** GET /api/build/undo's `plan.hash` for that `n`. */
10853
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/)
10854
+ });
10855
+ var CatalogPruneView = external_exports.object({
10856
+ files: external_exports.array(external_exports.object({ path: external_exports.string(), why: external_exports.string() })),
10857
+ /** A hash of the files listed and why, sent back by the confirm. */
10858
+ plan: external_exports.string()
10859
+ });
10860
+ var CatalogPruneRequest = external_exports.strictObject({
10861
+ count: external_exports.number().int().min(1),
10862
+ /** GET /api/build/prune's `plan`. */
10863
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/)
10864
+ });
10865
+ var CatalogUpgradeView = external_exports.object({
10866
+ pending: external_exports.boolean(),
10867
+ records: external_exports.number().int(),
10868
+ write: external_exports.array(external_exports.object({ path: external_exports.string(), records: external_exports.number().int(), repo: external_exports.string().optional() })),
10869
+ writes: external_exports.array(external_exports.object({
10870
+ path: external_exports.string(),
10871
+ what: external_exports.enum(["readers-slot", "legacy-joins", "copy", "build-manifest"]),
10872
+ bytes: external_exports.number().int(),
10873
+ sha256: external_exports.string()
10874
+ })),
10875
+ copy: external_exports.object({ dir: external_exports.string(), files: external_exports.number().int() }),
10876
+ firstBuildChanges: external_exports.array(external_exports.string()),
10877
+ /** The record files the first build gives differently, each with how (relative to catalog/generated). */
10878
+ changes: external_exports.array(external_exports.object({ path: external_exports.string(), how: external_exports.enum(["added", "changed", "removed"]) })),
10879
+ /**
10880
+ * The count of `changes` the confirm accepts (`atticus upgrade --yes --accept-changes <n>`);
10881
+ * 0 when the first build changes nothing and plain `--yes` applies it.
10882
+ */
10883
+ acceptChanges: external_exports.number().int(),
10884
+ applies: external_exports.boolean(),
10885
+ run: external_exports.string(),
10886
+ verifiable: external_exports.array(external_exports.string()),
10887
+ plan: external_exports.string(),
10888
+ /**
10889
+ * The upgrade's other steps that wait (GET /api/upgrade's `pending`). They may change an input
10890
+ * the slots record, so this step is confirmed only once they have run (Run the upgrade, on Home or on Catalog builds):
10891
+ * the confirm is refused (409) while any waits.
10892
+ */
10893
+ others: external_exports.array(external_exports.object({ id: external_exports.string(), summary: external_exports.string() }))
10894
+ });
10895
+ var CatalogUpgradeRequest = external_exports.strictObject({
10896
+ count: external_exports.number().int().min(1),
10897
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/),
10898
+ acceptChanges: external_exports.number().int().min(1).optional()
10899
+ });
10244
10900
  var FreshState = external_exports.enum([
10245
10901
  /** Facts cite files that changed, or source files changed: read again. */
10246
10902
  "stale",
@@ -10286,6 +10942,67 @@ var FreshView = external_exports.object({
10286
10942
  repos: external_exports.array(FreshRepo),
10287
10943
  problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
10288
10944
  });
10945
+ var CanaryRateView = external_exports.object({
10946
+ k: external_exports.number().int(),
10947
+ n: external_exports.number().int(),
10948
+ rate: external_exports.number().nullable(),
10949
+ low: external_exports.number().nullable(),
10950
+ high: external_exports.number().nullable()
10951
+ });
10952
+ var CanaryRepoView = external_exports.object({
10953
+ repo: external_exports.string(),
10954
+ /** The report's file, relative to the metarepo. */
10955
+ path: external_exports.string(),
10956
+ at: external_exports.string(),
10957
+ by: external_exports.string(),
10958
+ seed: external_exports.string(),
10959
+ commit: external_exports.string().optional(),
10960
+ stacks: external_exports.array(external_exports.string()),
10961
+ /** Each stack planted in, with the items planted there (`entry`, `call`, `topic-in`...). */
10962
+ covers: external_exports.array(external_exports.object({ stack: external_exports.string(), what: external_exports.array(external_exports.string()) })),
10963
+ /** The items the templates have that the repo couldn't serve, so weren't planted, and why. */
10964
+ skipped: external_exports.array(external_exports.object({ stack: external_exports.string(), what: external_exports.string(), reason: external_exports.string() })),
10965
+ /** Lines of the read's facts file that didn't read as facts, left out of the score. */
10966
+ unread: external_exports.number().int(),
10967
+ planted: external_exports.object({
10968
+ n: external_exports.number().int(),
10969
+ found: external_exports.number().int(),
10970
+ rejected: external_exports.number().int(),
10971
+ missed: external_exports.number().int()
10972
+ }),
10973
+ removed: external_exports.object({
10974
+ n: external_exports.number().int(),
10975
+ absent: external_exports.number().int(),
10976
+ kept: external_exports.number().int(),
10977
+ rejected: external_exports.number().int(),
10978
+ /** Named by a fact cited neither on the line nor beside it: in neither rate's count. */
10979
+ elsewhere: external_exports.number().int()
10980
+ }),
10981
+ recall: CanaryRateView,
10982
+ /** Removed lines the read still claimed at their place, kept by the verifier or not. */
10983
+ fabrication: CanaryRateView,
10984
+ /** Removed lines claimed by a fact the verifier kept: graded as backed, and wrong. */
10985
+ passed: CanaryRateView
10986
+ });
10987
+ var CanaryView = external_exports.object({
10988
+ reportsDir: external_exports.string(),
10989
+ latest: external_exports.array(CanaryRepoView),
10990
+ pending: external_exports.array(external_exports.object({ repo: external_exports.string(), at: external_exports.string(), seed: external_exports.string() })),
10991
+ rates: external_exports.object({
10992
+ /** The audit misread rate: backed claims of the sample answered wrong, of those answered. */
10993
+ misread: CanaryRateView,
10994
+ /** The canary pass-through rate: lines taken out, claimed and kept, of those taken out. */
10995
+ passed: CanaryRateView,
10996
+ recall: CanaryRateView,
10997
+ fabrication: CanaryRateView,
10998
+ caught: external_exports.number().int(),
10999
+ elsewhere: external_exports.number().int(),
11000
+ repos: external_exports.object({ audited: external_exports.number().int(), canaries: external_exports.number().int() }),
11001
+ covers: external_exports.array(external_exports.object({ stack: external_exports.string(), what: external_exports.array(external_exports.string()) }))
11002
+ }),
11003
+ commands: external_exports.object({ plant: external_exports.string(), score: external_exports.string(), report: external_exports.string() }),
11004
+ problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
11005
+ });
10289
11006
  var ChangeKnowledgeItem = external_exports.object({
10290
11007
  id: external_exports.string(),
10291
11008
  kind: external_exports.string(),
@@ -10425,6 +11142,12 @@ var RepoFactsView = external_exports.object({
10425
11142
  verify: external_exports.string(),
10426
11143
  problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
10427
11144
  });
11145
+ var RepoFactsBatch = external_exports.object({
11146
+ /** By repo, as asked: what GET /api/facts/{repo} gives. */
11147
+ facts: external_exports.record(external_exports.string(), RepoFactsView),
11148
+ /** By repo: the problem GET /api/facts/{repo} would have answered (a name refused, none). */
11149
+ problems: external_exports.record(external_exports.string(), external_exports.object({ status: external_exports.number().int(), title: external_exports.string(), detail: external_exports.string().optional() }))
11150
+ });
10428
11151
  var FactCorrectionRequest = external_exports.strictObject({
10429
11152
  fact: external_exports.string().min(1),
10430
11153
  action: external_exports.enum(["wrong", "edit"]),
@@ -10681,6 +11404,11 @@ var OutsideCallView = external_exports.object({
10681
11404
  interface: external_exports.string().optional(),
10682
11405
  /** The spec operation it reaches (its Endpoint id), when it matches one. */
10683
11406
  operation: external_exports.string().optional(),
11407
+ /**
11408
+ * 3.12.0 (beta.27): every operation it reaches, sorted, when it is more than one: a gateway
11409
+ * route that forwards a wildcard (`/accounts/*`) reaches every operation under it.
11410
+ */
11411
+ operations: external_exports.array(external_exports.string()).optional(),
10684
11412
  /** Through a gateway's forwarding call (the route and the gateway's call), when it is. */
10685
11413
  through: external_exports.object({ repo: external_exports.string(), at: external_exports.string() }).optional(),
10686
11414
  /** 2.44.0 (ADR 0160): the entry of another team's shared map that answers it. */
@@ -10713,6 +11441,11 @@ var OutsideSystemView = external_exports.object({
10713
11441
  ambiguous: external_exports.array(OutsideCallView.extend({ candidates: external_exports.array(external_exports.string()) })),
10714
11442
  /** Open questions about it: naming it, or citing a line one of its calls is on. */
10715
11443
  questions: external_exports.array(external_exports.object({ id: external_exports.string(), repo: external_exports.string(), question: external_exports.string() })),
11444
+ /**
11445
+ * 3.12.0 (beta.27): what in the configuration is at odds with it, in plain words (an alias in
11446
+ * the profile that is a host an estate repo answers on, whose calls go to that repo instead).
11447
+ */
11448
+ notes: external_exports.array(external_exports.string()).optional(),
10716
11449
  /** With no spec: how to add one. */
10717
11450
  addSpec: external_exports.array(external_exports.string()).optional(),
10718
11451
  /**
@@ -10938,10 +11671,23 @@ var StageThreadView = external_exports.object({
10938
11671
  waiting: external_exports.object({ runId: external_exports.string(), prompt: external_exports.string() }).optional(),
10939
11672
  /** The step's words, for POST /api/runs/handoff (the next round's prompt). */
10940
11673
  step: external_exports.array(external_exports.string()),
11674
+ /**
11675
+ * 3.12.0 (beta.27 review): the planning files a person wrote, when the stage never ran and they
11676
+ * stand for its work (state `done`); drafting again replaces them (`step` with --force).
11677
+ */
11678
+ byPerson: external_exports.array(external_exports.string()).optional(),
10941
11679
  /** Whether a reply is taken now, and if not, why. */
10942
11680
  reply: external_exports.object({ open: external_exports.boolean(), why: external_exports.string().optional() }),
10943
11681
  problems: external_exports.array(external_exports.object({ file: external_exports.string(), message: external_exports.string() }))
10944
11682
  });
11683
+ var ChangeProblems = external_exports.array(external_exports.object({
11684
+ /** The change's folder name, its id. */
11685
+ id: external_exports.string(),
11686
+ /** Metarepo-relative, with forward slashes. */
11687
+ file: external_exports.string(),
11688
+ line: external_exports.number().int().optional(),
11689
+ message: external_exports.string()
11690
+ }));
10945
11691
  var StageThreadPost = external_exports.discriminatedUnion("kind", [
10946
11692
  external_exports.strictObject({ kind: external_exports.literal("reply"), text: external_exports.string().trim().min(1).max(4e3) }),
10947
11693
  external_exports.strictObject({
@@ -11390,6 +12136,13 @@ var Health = external_exports.object({
11390
12136
  apiVersion: external_exports.string(),
11391
12137
  schemaVersion: external_exports.number().int(),
11392
12138
  root: external_exports.string(),
12139
+ /**
12140
+ * 3.12.0 (beta.27 re-review): the root as one key, to tell the metarepo a page started with
12141
+ * from another after a restart: its real path as the file system gives it (links and 8.3
12142
+ * names resolved, the folders' own case), never case-folded but for a Windows drive letter
12143
+ * (upper case). Compare this exactly, never `root`.
12144
+ */
12145
+ rootKey: external_exports.string().optional(),
11393
12146
  openspec: external_exports.string().optional(),
11394
12147
  user: external_exports.string(),
11395
12148
  /** 2.22.0: started with `atticus ui --full`, so the app offers every page, not only the six. */
@@ -11400,6 +12153,11 @@ var Health = external_exports.object({
11400
12153
  */
11401
12154
  metarepo: external_exports.boolean().optional()
11402
12155
  });
12156
+ var FactsApplyRequest = external_exports.strictObject({
12157
+ allowRemovals: external_exports.number().int().min(0).max(1e6).optional(),
12158
+ discardEdits: external_exports.number().int().min(0).max(1e6).optional(),
12159
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
12160
+ });
11403
12161
  var ScanRequest = external_exports.strictObject({
11404
12162
  repos: external_exports.array(RecordId).optional(),
11405
12163
  /** Ignore the cache and rescan everything. */
@@ -11411,7 +12169,19 @@ var ScanRequest = external_exports.strictObject({
11411
12169
  * which repo answers on an unknown host only for the repos the assistant has read (facts on
11412
12170
  * file); `askAll` asks for every repo, as the command line's `atticus scan` does.
11413
12171
  */
11414
- askAll: external_exports.boolean().optional()
12172
+ askAll: external_exports.boolean().optional(),
12173
+ /**
12174
+ * 3.12.0 (ADR 0195 point 4): confirms the large removals a refused build listed, with their
12175
+ * count (`--allow-removals`); any other count refuses again.
12176
+ */
12177
+ allowRemovals: external_exports.number().int().min(0).max(1e6).optional(),
12178
+ /** 3.12.0: discards the hand edits a refused build listed, with their count (`--discard-edits`). */
12179
+ discardEdits: external_exports.number().int().min(0).max(1e6).optional(),
12180
+ /**
12181
+ * 3.12.0: the `plan` of the refusal a count confirms (its job's result's `refused.plan`),
12182
+ * required with a count, as Apply's is.
12183
+ */
12184
+ plan: external_exports.string().regex(/^[0-9a-f]{64}$/).optional()
11415
12185
  });
11416
12186
  var RepoBranchesView = external_exports.object({
11417
12187
  id: RecordId,
@@ -11487,7 +12257,13 @@ var ChangeCockpit = external_exports.object({
11487
12257
  work: external_exports.string().optional(),
11488
12258
  stages: external_exports.array(external_exports.object({
11489
12259
  stage: external_exports.enum(["feature", "architecture", "stories"]),
12260
+ /**
12261
+ * The loop's state, or not-started. 3.12.0 (beta.27 review), as the plan gate reads it:
12262
+ * `person` when a person wrote the planning files the stage writes (it never ran; `files`
12263
+ * names them) and `skipped` when the change passed the stage without it running.
12264
+ */
11490
12265
  state: external_exports.string(),
12266
+ files: external_exports.array(external_exports.string()).optional(),
11491
12267
  drafts: external_exports.number().int(),
11492
12268
  rounds: external_exports.number().int(),
11493
12269
  openQuestions: external_exports.number().int()
@@ -11531,7 +12307,12 @@ var ProposeScope = external_exports.enum([
11531
12307
  /** 2.67.0 (UX re-walk): everything the app's work writes, for the one Propose on Home. */
11532
12308
  "work",
11533
12309
  /** 2.67.0 (UX review): the changes' snow.md, after filling a service-desk draft's fields. */
11534
- "service-desk"
12310
+ "service-desk",
12311
+ /**
12312
+ * 3.12.0 (beta.27 review): exactly the paths `atticus upgrade` changed (kept with its run) and
12313
+ * its stamp, .atticus/metarepo.yaml, for the upgrade panel's Propose; never other pending work.
12314
+ */
12315
+ "upgrade"
11535
12316
  ]);
11536
12317
  var ProposePlanView = external_exports.object({
11537
12318
  scope: ProposeScope,
@@ -11607,6 +12388,20 @@ var OwnerQuestionView = external_exports.object({
11607
12388
  channel: external_exports.string(),
11608
12389
  state: external_exports.enum(["sent", "answered", "overdue"]),
11609
12390
  answer: external_exports.string().optional(),
12391
+ /** 3.12.0 (beta.27 review): the owner's display name (teams.yaml), for a team named there. */
12392
+ ownerName: external_exports.string().optional(),
12393
+ /**
12394
+ * 3.12.0 (beta.27 review): when it was asked or sent (a send is on file in the question's own
12395
+ * record, catalog/curated/ownerquestion/<id>.yaml, for every machine), when that is. A gap's question with no `sentAt` wasn't sent, whatever `state` says (the
12396
+ * record's own state starts at `sent`).
12397
+ */
12398
+ sentAt: external_exports.string().optional(),
12399
+ /**
12400
+ * 3.12.0 (beta.27 review of the fix): its Send made a manual step that is still open (the step
12401
+ * whose approval ref is `owner-ask:<id>`, in the metarepo for every machine): asked, waiting for
12402
+ * a person to send it; the step and when it was made. Marked done, it is a send on record.
12403
+ */
12404
+ asked: external_exports.object({ step: external_exports.string(), at: external_exports.string() }).optional(),
11610
12405
  routeTo: external_exports.string().optional(),
11611
12406
  fill: external_exports.array(external_exports.object({ file: external_exports.string(), field: external_exports.string(), what: external_exports.string() })).optional(),
11612
12407
  records: external_exports.array(external_exports.string()),
@@ -12701,7 +13496,13 @@ var UpgradeView = external_exports.object({
12701
13496
  newer: external_exports.boolean(),
12702
13497
  /** The Atticus that last upgraded it. */
12703
13498
  stamp: external_exports.string().optional(),
12704
- pending: external_exports.array(external_exports.object({ id: external_exports.string(), summary: external_exports.string(), files: external_exports.array(external_exports.string()) }))
13499
+ pending: external_exports.array(external_exports.object({ id: external_exports.string(), summary: external_exports.string(), files: external_exports.array(external_exports.string()) })),
13500
+ /**
13501
+ * 3.12.0 (beta.27 review): the paths the upgrades run here changed and nobody proposed or
13502
+ * committed yet, besides the stamp. Final round: the panel reads them from the upgrade job's
13503
+ * result, and offers Propose for the stamp alone too.
13504
+ */
13505
+ upgraded: external_exports.array(external_exports.string()).optional()
12705
13506
  });
12706
13507
  var FileEditView = external_exports.object({
12707
13508
  path: external_exports.string(),
@@ -13055,7 +13856,13 @@ var StartCopilotRunRequest = external_exports.object({
13055
13856
  kind: CopilotRunKind,
13056
13857
  repos: external_exports.array(external_exports.string().min(1)).max(500).optional(),
13057
13858
  /** Read the repos whole again (`--force`). */
13058
- force: external_exports.boolean().optional()
13859
+ force: external_exports.boolean().optional(),
13860
+ /**
13861
+ * 3.12.0 (beta.27): the model's limit in tokens, as the person gives it in the dialog, passed
13862
+ * as --max-tokens. Needed when Atticus doesn't know it (`limit.known` false in
13863
+ * GET /api/copilot-runs/current); kept on this machine to fill the field next time.
13864
+ */
13865
+ maxTokens: external_exports.number().int().min(1e3).max(1e7).optional()
13059
13866
  });
13060
13867
  var CopilotRunState = external_exports.enum(["running", "done", "stopped", "failed"]);
13061
13868
  var CopilotRunTab = external_exports.object({
@@ -13096,6 +13903,19 @@ var CopilotRunView = external_exports.object({
13096
13903
  }),
13097
13904
  /** The last thing said: the error a failed run ended on, or how it ended. */
13098
13905
  message: external_exports.string().optional(),
13906
+ /**
13907
+ * 3.12.0 (beta.27): the repos the run stopped on, each after two Copilot sessions added nothing
13908
+ * to a part: why, and what verify rejected (its code and reason) when it rejected something.
13909
+ */
13910
+ problems: external_exports.array(external_exports.object({
13911
+ repo: external_exports.string(),
13912
+ part: external_exports.number().int().min(1).optional(),
13913
+ total: external_exports.number().int().min(1).optional(),
13914
+ message: external_exports.string(),
13915
+ rejected: external_exports.array(external_exports.object({ code: external_exports.string(), message: external_exports.string() })),
13916
+ /** How many were rejected in all (`rejected` lists the first ones). */
13917
+ rejectedCount: external_exports.number().int().min(0)
13918
+ })).optional(),
13099
13919
  tabs: external_exports.array(CopilotRunTab)
13100
13920
  });
13101
13921
  var CopilotRunCurrent = external_exports.object({
@@ -13104,7 +13924,34 @@ var CopilotRunCurrent = external_exports.object({
13104
13924
  /** Whether runtime.yaml allows copilot-acp here, and if not, why. */
13105
13925
  allowed: external_exports.boolean(),
13106
13926
  why: external_exports.string().optional(),
13107
- model: external_exports.string().optional()
13927
+ model: external_exports.string().optional(),
13928
+ /**
13929
+ * 3.12.0 (beta.27): the model's limit a run reads at. `known` with `tokens` and where it is set
13930
+ * (runtime.yaml's maxInput, or what atticus probe measured); else the dialog asks for it, filled
13931
+ * with `tokens` when there is one to offer (`last`: the value given for the last run on this
13932
+ * machine; `probe`: a limit atticus probe measured for another assistant).
13933
+ */
13934
+ limit: external_exports.object({
13935
+ known: external_exports.boolean(),
13936
+ tokens: external_exports.number().int().min(1).optional(),
13937
+ from: external_exports.enum(["runtime.yaml", "probe", "last"]).optional()
13938
+ }).optional(),
13939
+ /**
13940
+ * 3.12.0 (beta.27): the /atticus-* assistant files each Copilot session reads, as
13941
+ * `atticus assistant-files --check` says: those missing or out of date (`stale`), which the run
13942
+ * writes first, and those edited by hand or not Atticus's (`edited`), which refuse the run.
13943
+ */
13944
+ assistantFiles: external_exports.object({
13945
+ upToDate: external_exports.boolean(),
13946
+ stale: external_exports.array(external_exports.string()),
13947
+ edited: external_exports.array(external_exports.string()),
13948
+ /**
13949
+ * 3.12.0 (beta.27, additive): of `stale`, the files shared with a person (CLAUDE.md,
13950
+ * .github/copilot-instructions.md, ...) with no Atticus section yet, which the run adds
13951
+ * its section to after the person's own lines; the dialog names them.
13952
+ */
13953
+ shared: external_exports.array(external_exports.string()).optional()
13954
+ }).optional()
13108
13955
  });
13109
13956
  var ActivityKind = external_exports.enum([
13110
13957
  // The app's own jobs (ADR 0015), by their kind.
@@ -13167,6 +14014,13 @@ var ActivityEntry = external_exports.object({
13167
14014
  rev: external_exports.string().optional(),
13168
14015
  /** The route that stops it (POST), when the app can; a command stops in its terminal. */
13169
14016
  stop: external_exports.string().optional(),
14017
+ /** 3.12.0: Stop was asked and it is ending. */
14018
+ stopping: external_exports.boolean().optional(),
14019
+ /**
14020
+ * 3.12.0 (beta.27 review): how a `done` entry ended when it isn't plain done: `refused`, it
14021
+ * refused and wrote nothing (a scan's safety stop), neither done work nor a failure.
14022
+ */
14023
+ outcome: external_exports.enum(["refused"]).optional(),
13170
14024
  jobId: external_exports.string().optional(),
13171
14025
  copilotRunId: external_exports.string().optional(),
13172
14026
  /** A command's run id (its files in .atticus/logs/). */
@@ -13287,7 +14141,15 @@ var WorkItemSyncResult = external_exports.object({
13287
14141
  done: external_exports.array(external_exports.object({ key: external_exports.string(), action: external_exports.string(), id: external_exports.string() })),
13288
14142
  failed: external_exports.array(external_exports.object({ key: external_exports.string(), reason: external_exports.string() }))
13289
14143
  });
13290
- var SendOwnerAskRequest = external_exports.strictObject({ confirmation: Confirmation.optional() });
14144
+ var SendOwnerAskRequest = external_exports.strictObject({
14145
+ confirmation: Confirmation.optional(),
14146
+ /**
14147
+ * 3.12.0 (beta.27 review): the person chose Send again: a question whose own record says it
14148
+ * was sent (by anyone, from any machine) is sent through a live notifier only then (409
14149
+ * otherwise).
14150
+ */
14151
+ again: external_exports.boolean().optional()
14152
+ });
13291
14153
  var SentOwnerAsk = external_exports.object({
13292
14154
  /** sent: through the adapter; step: a manual step for a person; not-sent: why in `why`. */
13293
14155
  state: external_exports.enum(["sent", "step", "not-sent"]),
@@ -14200,6 +15062,180 @@ var OPS = {
14200
15062
  ok: { status: 200, schema: "FreshView", description: "OK" }
14201
15063
  }
14202
15064
  },
15065
+ "/api/facts": {
15066
+ get: {
15067
+ id: "getReposFacts",
15068
+ summary: "3.12.0: several repos' facts in one call, each as GET /api/facts/{repo} gives it, and the problem of each repo that can't be read (the Map's one read for all its repos)",
15069
+ tag: "workspace",
15070
+ params: [q("repo", str2, "A repo, once per repo (or several, comma-separated); at most 100")],
15071
+ ok: { status: 200, schema: "RepoFactsBatch", description: "OK" },
15072
+ errors: [400]
15073
+ }
15074
+ },
15075
+ "/api/trust/canaries": {
15076
+ get: {
15077
+ id: "getTrustCanaries",
15078
+ summary: "Canaries (ADR 0196): the latest canary of each repo (recall on what was planted, fabrication on what was commented out, what it covers), those planted here and not yet scored, and the audit misread rate and the canary pass-through rate side by side; files only, nothing run or written",
15079
+ tag: "workspace",
15080
+ ok: { status: 200, schema: "CanaryView", description: "OK" }
15081
+ }
15082
+ },
15083
+ "/api/crosscheck": {
15084
+ get: {
15085
+ id: "getCrossCheck",
15086
+ summary: "3.12.0 (ADR 0195 point 3): each repo's readers' cross-check counts: what the built-in readers found that its facts don't have, where they disagree, and what only the facts have; or why it isn't compared (no facts, no readers slot yet, a legacy slot). Reads files only",
15087
+ tag: "workspace",
15088
+ ok: { status: 200, schema: "CrossCheckView", description: "OK" }
15089
+ }
15090
+ },
15091
+ "/api/crosscheck/{repo}": {
15092
+ get: {
15093
+ id: "getRepoCrossCheck",
15094
+ summary: "3.12.0: one repo's cross-check with its items, each with the readers' and the facts' value and their citations, and whether it is dismissed. Reads files only",
15095
+ tag: "workspace",
15096
+ params: [p("repo")],
15097
+ ok: { status: 200, schema: "RepoCrossCheck", description: "OK" },
15098
+ errors: [400, 404]
15099
+ }
15100
+ },
15101
+ "/api/crosscheck/{repo}/dismiss": {
15102
+ post: {
15103
+ id: "dismissCrossCheckItem",
15104
+ summary: "3.12.0: dismiss a cross-check item at the readers' value it has now (listed again when that value changes), or take the dismissal back (undo): atticus catalog crosscheck <repo> --dismiss|--undismiss <key> as a local job, writing facts/<repo>.crosscheck.yaml. Changes no catalog record",
15105
+ tag: "workspace",
15106
+ params: [p("repo")],
15107
+ body: CrossCheckDismissRequest,
15108
+ ok: {
15109
+ status: 202,
15110
+ schema: "JobAccepted",
15111
+ description: "Started: its job's result is the code and the lines the command printed"
15112
+ },
15113
+ errors: [400, 404, 409]
15114
+ }
15115
+ },
15116
+ "/api/crosscheck/{repo}/promote": {
15117
+ get: {
15118
+ id: "getCrossCheckPromote",
15119
+ summary: "3.12.0 (ADR 0195 point 3): what promoting a readers-only item to assert would write: the by: person fact with the reader's citation, the cited line's text, the facts file it goes into and the hash the confirm sends back; or why it can't be promoted. Writes nothing",
15120
+ tag: "workspace",
15121
+ params: [
15122
+ p("repo"),
15123
+ q("key", { type: "string" }, "The item's key, as the cross-check names it")
15124
+ ],
15125
+ ok: { status: 200, schema: "CrossCheckPromoteView", description: "OK" },
15126
+ errors: [400, 404]
15127
+ },
15128
+ post: {
15129
+ id: "promoteCrossCheckItem",
15130
+ summary: "3.12.0: atticus catalog crosscheck <repo> --promote <key>, then atticus verify <repo>, as one local job: the by: person fact is added to facts/<repo>.jsonl (an edit to propose) and the verifier checks it on its line; GET /api/crosscheck/{repo} then says whether it verified. 409 when the fact is no longer the one previewed. Changes no catalog record (verify --write does, on Apply)",
15131
+ tag: "workspace",
15132
+ params: [p("repo")],
15133
+ body: CrossCheckPromoteRequest,
15134
+ ok: {
15135
+ status: 202,
15136
+ schema: "JobAccepted",
15137
+ description: "Started: its job's result is the code and the lines the commands printed"
15138
+ },
15139
+ errors: [400, 404, 409]
15140
+ }
15141
+ },
15142
+ "/api/build": {
15143
+ get: {
15144
+ id: "getCatalogBuild",
15145
+ summary: "3.12.0 (ADR 0195 points 4 and 7): each repo's source, what atticus catalog build would do now (nothing, the removals it writes, or its refusal with the removals and hand edits it lists and the counts that confirm them), and what the last build here changed. Builds in memory; writes nothing",
15146
+ tag: "scans",
15147
+ ok: { status: 200, schema: "CatalogBuildView", description: "OK" }
15148
+ },
15149
+ post: {
15150
+ id: "runCatalogBuild",
15151
+ summary: "3.12.0: atticus catalog build as a local job, confirming exactly the removals and hand edits listed with their counts (--allow-removals, --discard-edits); any other count refuses again and writes nothing",
15152
+ tag: "scans",
15153
+ body: CatalogBuildRequest,
15154
+ bodyOptional: true,
15155
+ ok: {
15156
+ status: 202,
15157
+ schema: "JobAccepted",
15158
+ description: "Started: its job's result is the code and the lines the build printed"
15159
+ },
15160
+ errors: [400, 409]
15161
+ }
15162
+ },
15163
+ "/api/build/edits/curate": {
15164
+ post: {
15165
+ id: "curateHandEdits",
15166
+ summary: "3.12.0 (ADR 0195 point 4): atticus catalog edits --curate then atticus catalog build, as one local job: each hand edit listed becomes a curated decision in catalog/curated/ (an edit to propose), and the build with them keeps what the edited files hold. 409 when the edits are no longer the count listed",
15167
+ tag: "scans",
15168
+ body: CatalogEditsRequest,
15169
+ ok: {
15170
+ status: 202,
15171
+ schema: "JobAccepted",
15172
+ description: "Started: its job's result is the code and the lines the command printed"
15173
+ },
15174
+ errors: [400, 409]
15175
+ }
15176
+ },
15177
+ "/api/build/undo": {
15178
+ get: {
15179
+ id: "getCatalogUndo",
15180
+ summary: "3.12.0 (ADR 0195 point 7): the builds kept to undo on this machine (the last five), newest first and numbered 1 (the latest) to 5, and the files taking back the n latest would put back (1 when left out). Writes nothing",
15181
+ tag: "scans",
15182
+ params: [q("n", { type: "integer" }, "How many of the latest builds to take back")],
15183
+ ok: { status: 200, schema: "CatalogUndoView", description: "OK" },
15184
+ errors: [400]
15185
+ },
15186
+ post: {
15187
+ id: "runCatalogUndo",
15188
+ summary: "3.12.0: atticus catalog undo <n> --yes as a local job: puts back the files listed, as they were before the n latest builds; its own undo copy is kept, so it can be undone. 409 when the plan is no longer the files listed",
15189
+ tag: "scans",
15190
+ body: CatalogUndoRequest,
15191
+ ok: {
15192
+ status: 202,
15193
+ schema: "JobAccepted",
15194
+ description: "Started: its job's result is the code and the lines the command printed"
15195
+ },
15196
+ errors: [400, 409]
15197
+ }
15198
+ },
15199
+ "/api/build/upgrade": {
15200
+ get: {
15201
+ id: "getCatalogUpgrade",
15202
+ summary: "3.12.0 (ADR 0195 point 6): the upgrade to source slots as a dry run, as atticus upgrade --json lists it: every file atticus upgrade --yes writes with its size and hash, the copy kept in generated-before-upgrade/, and the first build's changes (none, or it refuses). Writes nothing",
15203
+ tag: "scans",
15204
+ ok: { status: 200, schema: "CatalogUpgradeView", description: "OK" }
15205
+ },
15206
+ post: {
15207
+ id: "runCatalogUpgrade",
15208
+ summary: "3.12.0: atticus upgrade --yes as a local job, confirming the files listed (their count, typed by the person, and the listing's plan hash). 409 when the upgrade no longer waits, would refuse, or its files are no longer the ones listed",
15209
+ tag: "scans",
15210
+ body: CatalogUpgradeRequest,
15211
+ ok: {
15212
+ status: 202,
15213
+ schema: "JobAccepted",
15214
+ description: "Started: its job's result is the code and the lines the upgrade printed"
15215
+ },
15216
+ errors: [400, 409]
15217
+ }
15218
+ },
15219
+ "/api/build/prune": {
15220
+ get: {
15221
+ id: "getCatalogPrune",
15222
+ summary: "3.12.0 (ADR 0195 point 4): the slot files no build reads (repos no longer listed or archived, the upgrade's copy of the catalog), each with why. Writes nothing",
15223
+ tag: "scans",
15224
+ ok: { status: 200, schema: "CatalogPruneView", description: "OK" }
15225
+ },
15226
+ post: {
15227
+ id: "runCatalogPrune",
15228
+ summary: "3.12.0: atticus catalog prune --yes as a local job, removing exactly the files listed (an undo copy keeps them). 409 when the list is no longer the count listed",
15229
+ tag: "scans",
15230
+ body: CatalogPruneRequest,
15231
+ ok: {
15232
+ status: 202,
15233
+ schema: "JobAccepted",
15234
+ description: "Started: its job's result is the code and the lines the command printed"
15235
+ },
15236
+ errors: [400, 409]
15237
+ }
15238
+ },
14203
15239
  "/api/facts/{repo}": {
14204
15240
  get: {
14205
15241
  id: "getRepoFacts",
@@ -14347,12 +15383,21 @@ var OPS = {
14347
15383
  errors: [400, 409, 422]
14348
15384
  }
14349
15385
  },
15386
+ "/api/change-problems": {
15387
+ get: {
15388
+ id: "listChangeProblems",
15389
+ summary: "3.12.0 (beta.27 review): the changes whose change.yaml doesn't read, with the file, the line and why; GET /api/changes leaves them out",
15390
+ tag: "changes",
15391
+ ok: { status: 200, schema: "ChangeProblems", description: "OK" }
15392
+ }
15393
+ },
14350
15394
  "/api/facts/{repo}/apply": {
14351
15395
  post: {
14352
15396
  id: "applyFacts",
14353
- summary: "2.65.0 (ADR 0183): run atticus verify <repo> --write, as Apply after an answer or a correction",
15397
+ summary: "2.65.0 (ADR 0183): run atticus verify <repo> --write, as Apply after an answer or a correction; 3.12.0: with the counts that confirm a refused build",
14354
15398
  tag: "workspace",
14355
15399
  params: [p("repo")],
15400
+ body: FactsApplyRequest,
14356
15401
  ok: {
14357
15402
  status: 202,
14358
15403
  schema: "JobAccepted",
@@ -14398,12 +15443,12 @@ var OPS = {
14398
15443
  "/api/owner-questions/{id}/send": {
14399
15444
  post: {
14400
15445
  id: "sendOwnerQuestion",
14401
- summary: "3.6.0 (ADR 0191): send the owner question through the notify adapter to its owner, on the person's `owner-ask` confirmation; with manual notifications it is a step for a person, and with none it says to copy the text",
15446
+ summary: "3.6.0 (ADR 0191): send the owner question through the notify adapter to its owner, on the person's `owner-ask` confirmation; with no notifications set up it says to copy the text (`state: not-sent`). 3.12.0 (beta.27 review): a live send (`state: sent`) is written to the question's own record, catalog/curated/ownerquestion/<id>.yaml (`questionState: sent`, manual evidence first); a manual step (manual notifications, or a live notifier that couldn't start or fell back on the send) answers `state: step` with why and writes no record: the question says `asked` while the step is open, one step per question whoever sends it, and is sent on record once a person marks the step done. One whose record says sent is sent again through a live notifier only with `again` (409 Already sent without it); 409 Being sent while another send of it is under way",
14402
15447
  tag: "questions",
14403
15448
  params: [p("id")],
14404
15449
  body: SendOwnerAskRequest,
14405
15450
  ok: { status: 200, schema: "SentOwnerAsk", description: "Sent, or why not" },
14406
- errors: [400, 403, 404]
15451
+ errors: [400, 403, 404, 409]
14407
15452
  }
14408
15453
  },
14409
15454
  "/api/owner-questions/{id}/answer": {
@@ -14559,6 +15604,20 @@ var OPS = {
14559
15604
  errors: [400, 403, 404, 422]
14560
15605
  }
14561
15606
  },
15607
+ "/api/changes/{changeId}/artifacts/{artifact}/files": {
15608
+ get: {
15609
+ id: "getArtifactFiles",
15610
+ summary: "3.12.0: several files of a many-file artifact in one call (a change's stories), each as GET /api/changes/{changeId}/artifacts/{artifact}?file= gives it",
15611
+ tag: "changes",
15612
+ params: [
15613
+ p("changeId"),
15614
+ p("artifact", { schema: { type: "string", enum: ChangeArtifact.options } }),
15615
+ q("file", str2, "One file, relative to the change folder (stories/<id>.md), once per file; at most 200. A file that can't be read is in `problems`, the others answered")
15616
+ ],
15617
+ ok: { status: 200, schema: "ArtifactFiles", description: "OK" },
15618
+ errors: [400, 404]
15619
+ }
15620
+ },
14562
15621
  "/api/changes/{changeId}/artifacts/{artifact}": {
14563
15622
  get: {
14564
15623
  id: "getArtifact",
@@ -16106,6 +17165,7 @@ function openApiDocument() {
16106
17165
  InitiativeSavedView,
16107
17166
  ChangeDetail,
16108
17167
  ArtifactContent,
17168
+ ArtifactFiles,
16109
17169
  Task,
16110
17170
  RunView,
16111
17171
  RunList,
@@ -16197,11 +17257,20 @@ function openApiDocument() {
16197
17257
  MarkedNeed,
16198
17258
  TrustView,
16199
17259
  AnswerBoxResult,
17260
+ CrossCheckView,
17261
+ RepoCrossCheck,
17262
+ CatalogBuildView,
17263
+ CatalogUndoView,
17264
+ CatalogPruneView,
17265
+ CatalogUpgradeView,
17266
+ CrossCheckPromoteView,
16200
17267
  FreshView,
17268
+ CanaryView,
16201
17269
  ChangeKnowledgeView,
16202
17270
  KnowledgeConflictView,
16203
17271
  SetChangeKnowledgeResult,
16204
17272
  RepoFactsView,
17273
+ RepoFactsBatch,
16205
17274
  FactCorrectionResult,
16206
17275
  LinkCorrectionsResult,
16207
17276
  VerifyPreviewView,
@@ -16213,6 +17282,7 @@ function openApiDocument() {
16213
17282
  StageCommentResult,
16214
17283
  StageThreadView,
16215
17284
  StageThreadPostResult,
17285
+ ChangeProblems,
16216
17286
  PlacementView,
16217
17287
  StageDraftsView,
16218
17288
  CorrectionResult,
@@ -16329,6 +17399,7 @@ function stripMeta(s) {
16329
17399
 
16330
17400
  // packages/core/dist/merge.js
16331
17401
  import { createHash as createHash5 } from "node:crypto";
17402
+ var guessedLink = (d) => Array.isArray(d.flags) && d.flags.some((f) => JOIN_GUESS_FLAGS.includes(f));
16332
17403
  var DECLARED_TOPIC = "declared-topic";
16333
17404
  var short = (s, n = 6) => createHash5("sha256").update(s).digest("hex").slice(0, n);
16334
17405
  var MAX_RECORD_ID = 120;
@@ -16405,8 +17476,8 @@ function singularNoun(word) {
16405
17476
  }
16406
17477
  var singular = singularNoun;
16407
17478
  function endpointId(component, method, normalizedPath) {
16408
- const segs2 = normalizedPath.split("/").filter((s) => s && s !== "{}" && !/^v\d+$/i.test(s));
16409
- const last = segs2.at(-1) ?? "root";
17479
+ const segs3 = normalizedPath.split("/").filter((s) => s && s !== "{}" && !/^v\d+$/i.test(s));
17480
+ const last = segs3.at(-1) ?? "root";
16410
17481
  const slug = last.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
16411
17482
  const words = slug.split("-");
16412
17483
  const name = [...words.slice(0, -1), singular(words.at(-1) ?? "")].join("-") || "root";
@@ -16424,6 +17495,7 @@ function mergeCatalog(input) {
16424
17495
  const put = (key3, r) => byKey.set(key3, byKey.has(key3) ? combine(byKey.get(key3), r, known) : r);
16425
17496
  const loose = [];
16426
17497
  const dialectInterfaces = [];
17498
+ const topicEndpoints = [];
16427
17499
  const owners = /* @__PURE__ */ new Map();
16428
17500
  for (const r of input.records)
16429
17501
  if (r.kind === "DataStore" && typeof r.ownerComponent === "string")
@@ -16473,10 +17545,23 @@ function mergeCatalog(input) {
16473
17545
  } else if (r.kind === "Endpoint" && BY_ID_ENDPOINTS.has(String(r.endpointType)))
16474
17546
  put(`Typed|${r.id}`, r);
16475
17547
  else if (r.kind === "Endpoint")
16476
- put(`Topic|${r.pathOrTopic}`, r);
17548
+ topicEndpoints.push(r);
16477
17549
  else
16478
17550
  put(`${r.kind}|${r.id}`, r);
16479
17551
  }
17552
+ const defined = new Set(topicEndpoints.filter((r) => r.evidence.some((e) => e.side === "definition")).map((r) => String(r.pathOrTopic)));
17553
+ const ownTopicKeys = /* @__PURE__ */ new Map();
17554
+ for (const r of topicEndpoints) {
17555
+ const topic = String(r.pathOrTopic);
17556
+ if (defined.has(topic)) {
17557
+ put(`Topic|${topic}`, r);
17558
+ continue;
17559
+ }
17560
+ const key3 = `Topic|${topic}|${String(r.component ?? "")}`;
17561
+ if (!byKey.has(key3))
17562
+ ownTopicKeys.set(topic, [...ownTopicKeys.get(topic) ?? [], key3]);
17563
+ put(key3, r);
17564
+ }
16480
17565
  const endpoints = [...byKey.entries()].filter(([k]) => k.startsWith("Endpoint|"));
16481
17566
  const proposed = /* @__PURE__ */ new Map();
16482
17567
  for (const [k, e] of endpoints) {
@@ -16514,6 +17599,11 @@ function mergeCatalog(input) {
16514
17599
  return systemByPrefix.get(componentId);
16515
17600
  };
16516
17601
  const componentsOfSystem = (sys) => [...components.values()].filter((c) => c.system === sys).map((c) => c.id);
17602
+ const estateSystems = /* @__PURE__ */ new Set([
17603
+ ...input.repos.flatMap((r) => r.system ? [r.system] : []),
17604
+ ...[...components.values()].flatMap((c) => c.repo && c.system ? [String(c.system)] : [])
17605
+ ]);
17606
+ const vendorBox = (id) => systemsById.get(id)?.boundary === "vendor" && !estateSystems.has(id);
16517
17607
  const resolveComponent = (name, ev) => {
16518
17608
  if (components.has(name))
16519
17609
  return name;
@@ -16529,9 +17619,18 @@ function mergeCatalog(input) {
16529
17619
  const inSys = componentsOfSystem(s.id);
16530
17620
  if (inSys.length === 1)
16531
17621
  return inSys[0];
17622
+ if (inSys.length === 0 && vendorBox(s.id))
17623
+ return s.id;
16532
17624
  }
16533
17625
  }
16534
17626
  const sys = systemOf(name);
17627
+ if (sys && vendorBox(sys)) {
17628
+ const inSys = componentsOfSystem(sys);
17629
+ if (inSys.length === 0)
17630
+ return sys;
17631
+ if (inSys.length === 1)
17632
+ return inSys[0];
17633
+ }
16535
17634
  if (sys) {
16536
17635
  const c = {
16537
17636
  schemaVersion: 1,
@@ -16675,17 +17774,24 @@ function mergeCatalog(input) {
16675
17774
  evidence: unionEvidence(caller, gwEv, callee)
16676
17775
  });
16677
17776
  }
16678
- for (const d of dialectInterfaces) {
17777
+ for (const raw of dialectInterfaces) {
17778
+ const target = resolveComponent(String(raw.to), raw.evidence[0]);
17779
+ const d = target && target !== raw.to && !components.has(String(raw.to)) && vendorBox(systemOf(target) ?? target) ? {
17780
+ ...raw,
17781
+ to: target,
17782
+ id: interfaceId(String(raw.from), target, raw.method, String(raw.normalizedPath))
17783
+ } : raw;
16679
17784
  const ep = findEndpoint(String(d.to), d.method, String(d.normalizedPath));
16680
17785
  const callee = calleeEvidence(ep);
16681
- resolveComponent(String(d.to), d.evidence[0]);
16682
17786
  addInterface({
16683
17787
  ...d,
16684
17788
  ...ep ? { endpoint: ep.id } : {},
16685
17789
  evidence: unionEvidence(d.evidence, callee),
16686
17790
  // A person's word stays asserted (A-callers): finding the callee's code doesn't prove the
16687
- // caller, which nobody read, makes the call.
16688
- confidence: d.confidence === "asserted" ? "asserted" : callee.length > 0 ? "verified" : d.confidence
17791
+ // caller, which nobody read, makes the call. Beta.27 (a user's Map): nor does it prove a
17792
+ // guess right. An Interface the facts join guessed (by path, a host's label, J0's and J1's
17793
+ // guesses) stays as the join made it: never verified because its callee's line is found.
17794
+ confidence: d.confidence === "asserted" ? "asserted" : guessedLink(d) ? d.confidence : callee.length > 0 ? "verified" : d.confidence
16689
17795
  });
16690
17796
  }
16691
17797
  resolveTypedCalls({
@@ -16732,12 +17838,20 @@ function mergeCatalog(input) {
16732
17838
  const firstCodePub = [...pub.entries()].find(([, ev]) => ev.some((e) => e.source === "code"))?.[0];
16733
17839
  if (ep && (ep.component === "unknown" || !ep.component) && firstCodePub)
16734
17840
  ep.component = firstCodePub;
17841
+ const own = (ownTopicKeys.get(topic) ?? []).map((k) => byKey.get(k));
17842
+ if (!ep && firstCodePub) {
17843
+ for (const x of own)
17844
+ if (x.component === "unknown" || !x.component)
17845
+ x.component = firstCodePub;
17846
+ }
17847
+ const epOf = (p2, s) => ep ?? own.find((x) => x.component === s) ?? own.find((x) => x.component === p2);
16735
17848
  for (const [p2, pev] of [...pub.entries()].sort()) {
16736
17849
  for (const [s, sev] of [...sub.entries()].sort()) {
16737
17850
  if (p2 === s)
16738
17851
  continue;
16739
17852
  const pc = pev.filter((e) => e.source === "code");
16740
17853
  const sc = sev.filter((e) => e.source === "code");
17854
+ const pairEp = epOf(p2, s);
16741
17855
  addInterface({
16742
17856
  schemaVersion: 1,
16743
17857
  kind: "Interface",
@@ -16746,7 +17860,10 @@ function mergeCatalog(input) {
16746
17860
  confidence: pc.length > 0 && sc.length > 0 ? "verified" : "inferred",
16747
17861
  from: p2,
16748
17862
  to: s,
16749
- ...ep ? { endpoint: ep.id } : {},
17863
+ // The topic's Endpoint: its definition's, or one either end of this pair serves. Another
17864
+ // consumer's own endpoint for the topic (a facts entry) isn't this pair's (ADR 0195,
17865
+ // locality: a repo's read changes only the joins it is part of).
17866
+ ...pairEp && (def.length > 0 || pairEp.component === p2 || pairEp.component === s) ? { endpoint: pairEp.id } : {},
16750
17867
  via: "event-bus",
16751
17868
  normalizedPath: topic,
16752
17869
  sync: "async",
@@ -17139,8 +18256,21 @@ function recordReferences(record) {
17139
18256
  var PROTECTED = ["kind", "id", "schemaVersion", "confidence", "evidence"];
17140
18257
  var SCOPES = ["diagram", "triage"];
17141
18258
  var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
18259
+ function byDecisionTime(a, b) {
18260
+ const x = Date.parse(a.at);
18261
+ const y = Date.parse(b.at);
18262
+ const xs = Number.isNaN(x);
18263
+ const ys = Number.isNaN(y);
18264
+ if (xs !== ys)
18265
+ return xs ? 1 : -1;
18266
+ if (!xs && x !== y)
18267
+ return x < y ? -1 : 1;
18268
+ if (xs && a.at !== b.at)
18269
+ return a.at < b.at ? -1 : 1;
18270
+ return a.id === b.id ? 0 : a.id < b.id ? -1 : 1;
18271
+ }
17142
18272
  function applyCurated(records, decisions) {
17143
- const list = decisions.filter((d) => d.kind === "CuratedDecision").filter((d) => d.status === "current").sort((a, b) => a.at === b.at ? a.id < b.id ? -1 : 1 : a.at < b.at ? -1 : 1);
18273
+ const list = decisions.filter((d) => d.kind === "CuratedDecision").filter((d) => d.status === "current").sort(byDecisionTime);
17144
18274
  const work = records.filter((r) => r.kind !== "CuratedDecision").map((r) => r);
17145
18275
  const current = new Map(work.map((r, i) => [i, r]));
17146
18276
  const dropped = /* @__PURE__ */ new Set();
@@ -17272,7 +18402,7 @@ function applyCurated(records, decisions) {
17272
18402
  var article2 = (kind) => /^[AEIOU]/.test(kind) ? `an ${kind}` : `a ${kind}`;
17273
18403
 
17274
18404
  // packages/core/dist/migrate.js
17275
- var import_yaml10 = __toESM(require_dist(), 1);
18405
+ var import_yaml11 = __toESM(require_dist(), 1);
17276
18406
  import { readdir as readdir4, readFile as readFile5 } from "node:fs/promises";
17277
18407
  import { join as join6, relative as relative2, sep as sep2 } from "node:path";
17278
18408
 
@@ -17392,7 +18522,7 @@ function verdictOf(text4, o) {
17392
18522
  }
17393
18523
  let data;
17394
18524
  try {
17395
- data = (0, import_yaml10.parse)(text4);
18525
+ data = (0, import_yaml11.parse)(text4);
17396
18526
  } catch {
17397
18527
  return "skip";
17398
18528
  }
@@ -17438,7 +18568,7 @@ async function migrateCatalog(dir, o = {}) {
17438
18568
  }
17439
18569
  let data;
17440
18570
  try {
17441
- data = (0, import_yaml10.parse)(text4);
18571
+ data = (0, import_yaml11.parse)(text4);
17442
18572
  } catch {
17443
18573
  continue;
17444
18574
  }
@@ -17474,37 +18604,37 @@ function keepLineEndings(was, now) {
17474
18604
  }
17475
18605
 
17476
18606
  // packages/core/dist/gates-migrate.js
17477
- var import_yaml11 = __toESM(require_dist(), 1);
18607
+ var import_yaml12 = __toESM(require_dist(), 1);
17478
18608
  function migrateGatesText(text4) {
17479
- const doc = (0, import_yaml11.parseDocument)(text4);
17480
- if (!(0, import_yaml11.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
18609
+ const doc = (0, import_yaml12.parseDocument)(text4);
18610
+ if (!(0, import_yaml12.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
17481
18611
  return { text: text4, changed: false };
17482
18612
  doc.set("schemaVersion", GATES_SCHEMA_VERSION);
17483
18613
  const gates = doc.get("gates");
17484
- if ((0, import_yaml11.isSeq)(gates)) {
18614
+ if ((0, import_yaml12.isSeq)(gates)) {
17485
18615
  for (const g of gates.items)
17486
- if ((0, import_yaml11.isMap)(g) && !g.has("maxAuthorRounds"))
18616
+ if ((0, import_yaml12.isMap)(g) && !g.has("maxAuthorRounds"))
17487
18617
  g.set("maxAuthorRounds", 2);
17488
18618
  }
17489
18619
  return { text: keepLineEndings(text4, doc.toString({ lineWidth: 0 })), changed: true };
17490
18620
  }
17491
18621
 
17492
18622
  // packages/core/dist/change-types-migrate.js
17493
- var import_yaml12 = __toESM(require_dist(), 1);
18623
+ var import_yaml13 = __toESM(require_dist(), 1);
17494
18624
  function migrateChangeTypesText(text4) {
17495
- const doc = (0, import_yaml12.parseDocument)(text4);
17496
- if (!(0, import_yaml12.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
18625
+ const doc = (0, import_yaml13.parseDocument)(text4);
18626
+ if (!(0, import_yaml13.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
17497
18627
  return { text: text4, changed: false };
17498
18628
  doc.set("schemaVersion", CHANGE_TYPES_SCHEMA_VERSION);
17499
18629
  return { text: keepLineEndings(text4, doc.toString({ lineWidth: 0 })), changed: true };
17500
18630
  }
17501
18631
 
17502
18632
  // packages/core/dist/sources-migrate.js
17503
- var import_yaml13 = __toESM(require_dist(), 1);
18633
+ var import_yaml14 = __toESM(require_dist(), 1);
17504
18634
  function migrateSourcesText(text4, o = {}) {
17505
18635
  const to = o.to ?? SOURCES_SCHEMA_VERSION;
17506
- const doc = (0, import_yaml13.parseDocument)(text4);
17507
- if (!(0, import_yaml13.isMap)(doc.contents))
18636
+ const doc = (0, import_yaml14.parseDocument)(text4);
18637
+ if (!(0, import_yaml14.isMap)(doc.contents))
17508
18638
  return { text: text4, changed: false };
17509
18639
  const v = doc.get("schemaVersion");
17510
18640
  if (typeof v !== "number" || v >= to || o.from !== void 0 && v !== o.from)
@@ -17514,10 +18644,10 @@ function migrateSourcesText(text4, o = {}) {
17514
18644
  }
17515
18645
 
17516
18646
  // packages/core/dist/runtime-migrate.js
17517
- var import_yaml14 = __toESM(require_dist(), 1);
18647
+ var import_yaml15 = __toESM(require_dist(), 1);
17518
18648
  function migrateRuntimeText(text4) {
17519
- const doc = (0, import_yaml14.parseDocument)(text4);
17520
- if (!(0, import_yaml14.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
18649
+ const doc = (0, import_yaml15.parseDocument)(text4);
18650
+ if (!(0, import_yaml15.isMap)(doc.contents) || doc.get("schemaVersion") !== 1)
17521
18651
  return { text: text4, changed: false };
17522
18652
  const line = /^schemaVersion:[ \t]*1[ \t]*(#.*)?$/m;
17523
18653
  if (line.test(text4))
@@ -17534,8 +18664,8 @@ function namesCopilotAcp(doc) {
17534
18664
  return js.copilotAcp !== void 0 || allowed.includes("copilot-acp") || js.modes?.default === "copilot-acp";
17535
18665
  }
17536
18666
  function migrateRuntimeV3Text(text4) {
17537
- const doc = (0, import_yaml14.parseDocument)(text4);
17538
- if (doc.errors.length || !(0, import_yaml14.isMap)(doc.contents))
18667
+ const doc = (0, import_yaml15.parseDocument)(text4);
18668
+ if (doc.errors.length || !(0, import_yaml15.isMap)(doc.contents))
17539
18669
  return { text: text4, changed: false };
17540
18670
  const v = doc.get("schemaVersion");
17541
18671
  if (v !== 1 && v !== 2 || !namesCopilotAcp(doc))
@@ -17550,8 +18680,8 @@ function migrateRuntimeV3Text(text4) {
17550
18680
  return { text: doc.toString({ lineWidth: 0 }), changed: true };
17551
18681
  }
17552
18682
  function migrateRuntimeV4Text(text4) {
17553
- const doc = (0, import_yaml14.parseDocument)(text4);
17554
- if (doc.errors.length || !(0, import_yaml14.isMap)(doc.contents))
18683
+ const doc = (0, import_yaml15.parseDocument)(text4);
18684
+ if (doc.errors.length || !(0, import_yaml15.isMap)(doc.contents))
17555
18685
  return { text: text4, changed: false };
17556
18686
  const v = doc.get("schemaVersion");
17557
18687
  if (v !== 1 && v !== 2 && v !== 3 || !doc.has("decide"))
@@ -18167,13 +19297,13 @@ function readTarGz(bytes, limits = {}) {
18167
19297
  }
18168
19298
 
18169
19299
  // packages/core/dist/questions.js
18170
- var import_yaml16 = __toESM(require_dist(), 1);
19300
+ var import_yaml17 = __toESM(require_dist(), 1);
18171
19301
  import { createHash as createHash8 } from "node:crypto";
18172
19302
  import { mkdir as mkdir2, readdir as readdir7, readFile as readFile8 } from "node:fs/promises";
18173
19303
  import { join as join9 } from "node:path";
18174
19304
 
18175
19305
  // packages/core/dist/judgments.js
18176
- var import_yaml15 = __toESM(require_dist(), 1);
19306
+ var import_yaml16 = __toESM(require_dist(), 1);
18177
19307
  import { createHash as createHash7 } from "node:crypto";
18178
19308
  import { mkdir, readdir as readdir6, readFile as readFile7 } from "node:fs/promises";
18179
19309
  import { join as join8 } from "node:path";
@@ -18207,7 +19337,7 @@ function fileJudgments(root) {
18207
19337
  const text4 = await readFile7(fileOf2(kind, key3), "utf8").catch(() => void 0);
18208
19338
  if (text4 === void 0)
18209
19339
  return void 0;
18210
- const r = Judgment.safeParse((0, import_yaml15.parse)(text4));
19340
+ const r = Judgment.safeParse((0, import_yaml16.parse)(text4));
18211
19341
  return r.success && r.data.kind === kind && r.data.key === key3 ? r.data : void 0;
18212
19342
  };
18213
19343
  return {
@@ -18231,7 +19361,7 @@ ${toCanonicalYaml(next, ["schemaVersion", "kind", "key", "verdict", "value"])}`)
18231
19361
  for (const n of (await readdir6(join8(dir, k)).catch(() => [])).filter((x) => x.endsWith(".yaml")).sort()) {
18232
19362
  const file = `${rel}/${k}/${n}`;
18233
19363
  try {
18234
- const r = Judgment.safeParse((0, import_yaml15.parse)(await readFile7(join8(dir, k, n), "utf8")));
19364
+ const r = Judgment.safeParse((0, import_yaml16.parse)(await readFile7(join8(dir, k, n), "utf8")));
18235
19365
  if (r.success)
18236
19366
  judgments.push(r.data);
18237
19367
  else
@@ -18508,9 +19638,9 @@ var lcp = (a, b) => {
18508
19638
  return a.slice(0, i);
18509
19639
  };
18510
19640
  var longest = (xs) => xs.length ? [...xs.reduce((a, b) => b.length > a.length ? b : a)] : void 0;
18511
- var fixed = (segs2) => {
18512
- const i = segs2.findIndex(isPlaceholder);
18513
- return i < 0 ? [...segs2] : segs2.slice(0, i);
19641
+ var fixed = (segs3) => {
19642
+ const i = segs3.findIndex(isPlaceholder);
19643
+ return i < 0 ? [...segs3] : segs3.slice(0, i);
18514
19644
  };
18515
19645
  function deriveMatch(item, siblings) {
18516
19646
  if (item.topic) {
@@ -18699,10 +19829,12 @@ async function routeQuestion(root, id, o) {
18699
19829
  return next;
18700
19830
  }
18701
19831
  var fileOf = (root, id) => join9(questionsDirOf(root), `${id}.yaml`);
19832
+ var questionFileOf = (root, id) => fileOf(root, id);
19833
+ var questionFileText = (q2) => `# A question from ${q2.askedBy.command} (ADR 0078). Answer it with atticus questions answer ${q2.id}, or in the app.
19834
+ ${(0, import_yaml17.stringify)(Question.parse(q2))}`;
18702
19835
  async function write(root, q2, before) {
18703
19836
  await mkdir2(questionsDirOf(root), { recursive: true });
18704
- const text4 = `# A question from ${q2.askedBy.command} (ADR 0078). Answer it with atticus questions answer ${q2.id}, or in the app.
18705
- ${(0, import_yaml16.stringify)(Question.parse(q2))}`;
19837
+ const text4 = questionFileText(q2);
18706
19838
  if (before)
18707
19839
  await writeFileIfUnchanged(fileOf(root, q2.id), before.text, text4);
18708
19840
  else
@@ -18717,7 +19849,7 @@ async function readQuestionText(root, id) {
18717
19849
  } catch {
18718
19850
  return void 0;
18719
19851
  }
18720
- const data = (0, import_yaml16.parse)(text4);
19852
+ const data = (0, import_yaml17.parse)(text4);
18721
19853
  const newer2 = newerQuestion(data);
18722
19854
  if (newer2)
18723
19855
  throw new Error(`${questionsRelOf(root)}/${id}.yaml was ${newer2}`);
@@ -18734,7 +19866,7 @@ async function readQuestion(root, id) {
18734
19866
  return (await readQuestionText(root, id))?.q;
18735
19867
  }
18736
19868
  function questionOfText(text4) {
18737
- const data = (0, import_yaml16.parse)(text4);
19869
+ const data = (0, import_yaml17.parse)(text4);
18738
19870
  const newer2 = newerQuestion(data);
18739
19871
  if (newer2)
18740
19872
  return { error: newer2 };
@@ -18814,22 +19946,22 @@ function sameQuestionInputs(repo, d, existing) {
18814
19946
  }
18815
19947
  var ANSWERED_BY = "answered-by";
18816
19948
  var ANSWERED_BY_VERSION = 1;
18817
- function answeredByInputs(repo, d, answered) {
19949
+ function answeredByInputs(repo, d, answered2) {
18818
19950
  return {
18819
19951
  v: ANSWERED_BY_VERSION,
18820
19952
  repo,
18821
19953
  new: { question: d.question.trim(), evidence: [...d.evidence].sort() },
18822
19954
  answered: {
18823
- id: answered.id,
18824
- question: answered.question.trim(),
18825
- answer: (answerWords(answered) ?? "").trim()
19955
+ id: answered2.id,
19956
+ question: answered2.question.trim(),
19957
+ answer: (answerWords(answered2) ?? "").trim()
18826
19958
  }
18827
19959
  };
18828
19960
  }
18829
- function namedBeyondAnswer(d, answered, repo = "") {
19961
+ function namedBeyondAnswer(d, answered2, repo = "") {
18830
19962
  const known = /* @__PURE__ */ new Set([
18831
- ...namedIdentifiers(answered.question, repo),
18832
- ...namedIdentifiers(answered.answer, repo)
19963
+ ...namedIdentifiers(answered2.question, repo),
19964
+ ...namedIdentifiers(answered2.answer, repo)
18833
19965
  ]);
18834
19966
  return [...namedIdentifiers(d.question, repo)].filter((n) => !known.has(n));
18835
19967
  }
@@ -18900,8 +20032,8 @@ async function raiseQuestions(root, drafts, by, o = {}) {
18900
20032
  }
18901
20033
  others ??= (await listQuestions(root, { repo: by.repo })).questions;
18902
20034
  const cands = candidatesFor(by.repo, d, by.step, others).filter((x) => !differentThings(d, x, by.repo));
18903
- const answered = others.filter((x) => x.state === "answered" && (x.id === d.sameAs?.id || sameTarget(d, x, by.repo)) && namedBeyondAnswer(d, { question: x.question, answer: answerWords(x) ?? "" }, by.repo).length === 0);
18904
- plans.push({ i, d, q: q2, cands, answered });
20035
+ const answered2 = others.filter((x) => x.state === "answered" && (x.id === d.sameAs?.id || sameTarget(d, x, by.repo)) && namedBeyondAnswer(d, { question: x.question, answer: answerWords(x) ?? "" }, by.repo).length === 0);
20036
+ plans.push({ i, d, q: q2, cands, answered: answered2 });
18905
20037
  }
18906
20038
  const decides = /* @__PURE__ */ new Map();
18907
20039
  const open = [];
@@ -19050,7 +20182,7 @@ async function raiseQuestions(root, drafts, by, o = {}) {
19050
20182
  function olderQuestionText(text4) {
19051
20183
  let data;
19052
20184
  try {
19053
- data = (0, import_yaml16.parse)(text4);
20185
+ data = (0, import_yaml17.parse)(text4);
19054
20186
  } catch {
19055
20187
  return false;
19056
20188
  }
@@ -19076,7 +20208,7 @@ async function migrateQuestions(root, o = {}) {
19076
20208
  let data;
19077
20209
  try {
19078
20210
  text4 = await readFile8(file, "utf8");
19079
- data = (0, import_yaml16.parse)(text4);
20211
+ data = (0, import_yaml17.parse)(text4);
19080
20212
  } catch {
19081
20213
  break;
19082
20214
  }
@@ -19111,7 +20243,7 @@ async function migrateQuestions(root, o = {}) {
19111
20243
  var reusedLine = (q2) => `${q2.id} was already asked by ${q2.askedBy.command}: "${q2.question.trim()}" This step ${q2.state === "answered" ? "reads its answer" : "waits on the same answer"} instead of asking again.`;
19112
20244
  async function repoTypeSkillRel(root, type) {
19113
20245
  const pack = isAdopted(root) ? ".atticus/org-pack" : "org-pack";
19114
- const listed = await readFile8(join9(root, pack, "repo-types", type, "type.yaml"), "utf8").then((t) => (0, import_yaml16.parse)(t)?.skills).catch(() => void 0);
20246
+ const listed = await readFile8(join9(root, pack, "repo-types", type, "type.yaml"), "utf8").then((t) => (0, import_yaml17.parse)(t)?.skills).catch(() => void 0);
19115
20247
  const first = Array.isArray(listed) && typeof listed[0] === "string" ? listed[0] : void 0;
19116
20248
  return `${pack}/${first ?? `process/skills/${type}/SKILL.md`}`;
19117
20249
  }
@@ -19270,7 +20402,7 @@ async function answerQuestion(root, id, a) {
19270
20402
  throw new QuestionError("bad-answer", why);
19271
20403
  }
19272
20404
  const skill = level === "repo-type" ? await repoTypeSkillRel(root, scopeId) : void 0;
19273
- const answered = Question.parse({
20405
+ const answered2 = Question.parse({
19274
20406
  ...q2,
19275
20407
  state: "answered",
19276
20408
  answer: {
@@ -19333,7 +20465,7 @@ async function answerQuestion(root, id, a) {
19333
20465
  throw new QuestionError("bad-answer", e.message.split("\n")[0]);
19334
20466
  }
19335
20467
  }
19336
- await write(root, answered, read);
20468
+ await write(root, answered2, read);
19337
20469
  const covered = [];
19338
20470
  if (hosts && match && !isPathMatch(match))
19339
20471
  for (const x of (await listQuestions(root, { state: "open", step: HOSTS_STEP })).questions) {
@@ -19353,35 +20485,35 @@ async function answerQuestion(root, id, a) {
19353
20485
  ...covered.length ? { covered } : {}
19354
20486
  };
19355
20487
  if (!skill)
19356
- return { question: answered, ...extra };
20488
+ return { question: answered2, ...extra };
19357
20489
  const file = join9(root, ...skill.split("/"));
19358
20490
  let body;
19359
20491
  try {
19360
20492
  body = await readFile8(file, "utf8");
19361
20493
  } catch {
19362
- return { question: answered, ...extra, skill: { path: skill, written: false } };
20494
+ return { question: answered2, ...extra, skill: { path: skill, written: false } };
19363
20495
  }
19364
20496
  try {
19365
- await writeFileIfUnchanged(file, body, withSkillAnswer(body, answered));
20497
+ await writeFileIfUnchanged(file, body, withSkillAnswer(body, answered2));
19366
20498
  } catch (e) {
19367
20499
  if (!(e instanceof FileChangedError))
19368
20500
  throw e;
19369
20501
  const now = await readFile8(file, "utf8").catch(() => void 0);
19370
20502
  if (now === void 0)
19371
- return { question: answered, ...extra, skill: { path: skill, written: false } };
20503
+ return { question: answered2, ...extra, skill: { path: skill, written: false } };
19372
20504
  try {
19373
- await writeFileIfUnchanged(file, now, withSkillAnswer(now, answered));
20505
+ await writeFileIfUnchanged(file, now, withSkillAnswer(now, answered2));
19374
20506
  } catch (again) {
19375
20507
  if (again instanceof FileChangedError)
19376
- return { question: answered, ...extra, skill: { path: skill, written: false } };
20508
+ return { question: answered2, ...extra, skill: { path: skill, written: false } };
19377
20509
  throw again;
19378
20510
  }
19379
20511
  }
19380
- return { question: answered, ...extra, skill: { path: skill, written: true } };
20512
+ return { question: answered2, ...extra, skill: { path: skill, written: true } };
19381
20513
  }
19382
20514
 
19383
20515
  // packages/core/dist/repo-reads.js
19384
- var import_yaml17 = __toESM(require_dist(), 1);
20516
+ var import_yaml18 = __toESM(require_dist(), 1);
19385
20517
  import { readFile as readFile9, stat as stat2 } from "node:fs/promises";
19386
20518
  import { join as join10, resolve as resolve2 } from "node:path";
19387
20519
  var FULL_SHA = /^[0-9a-f]{40,64}$/;
@@ -19439,7 +20571,7 @@ async function repoReadOf(root, repo) {
19439
20571
  }
19440
20572
  let report;
19441
20573
  try {
19442
- report = reportText === void 0 ? void 0 : (0, import_yaml17.parse)(reportText);
20574
+ report = reportText === void 0 ? void 0 : (0, import_yaml18.parse)(reportText);
19443
20575
  } catch {
19444
20576
  why.push("the verifier's report can't be read");
19445
20577
  }
@@ -19497,7 +20629,7 @@ function callsOfQuestion(q2, facts) {
19497
20629
  }
19498
20630
 
19499
20631
  // packages/core/dist/question-order.js
19500
- var import_yaml18 = __toESM(require_dist(), 1);
20632
+ var import_yaml19 = __toESM(require_dist(), 1);
19501
20633
  import { readdir as readdir8, readFile as readFile10 } from "node:fs/promises";
19502
20634
  import { join as join11 } from "node:path";
19503
20635
  var LANDED = /* @__PURE__ */ new Set(["released", "archived", "post-release-review"]);
@@ -19513,7 +20645,7 @@ async function changesInFlight(root) {
19513
20645
  continue;
19514
20646
  let state;
19515
20647
  try {
19516
- state = (0, import_yaml18.parse)(raw)?.state;
20648
+ state = (0, import_yaml19.parse)(raw)?.state;
19517
20649
  } catch {
19518
20650
  continue;
19519
20651
  }
@@ -19525,7 +20657,7 @@ async function changesInFlight(root) {
19525
20657
  function citedQuestions(raw) {
19526
20658
  let f;
19527
20659
  try {
19528
- f = (0, import_yaml18.parse)(raw);
20660
+ f = (0, import_yaml19.parse)(raw);
19529
20661
  } catch {
19530
20662
  return [];
19531
20663
  }
@@ -19601,7 +20733,7 @@ function orderQuestions(questions, weights) {
19601
20733
  }
19602
20734
 
19603
20735
  // packages/core/dist/question-owners.js
19604
- var import_yaml19 = __toESM(require_dist(), 1);
20736
+ var import_yaml20 = __toESM(require_dist(), 1);
19605
20737
  import { readFile as readFile11 } from "node:fs/promises";
19606
20738
  import { join as join12 } from "node:path";
19607
20739
  async function readTeams(root) {
@@ -19611,7 +20743,7 @@ async function readTeams(root) {
19611
20743
  return { teams: [] };
19612
20744
  let data;
19613
20745
  try {
19614
- data = (0, import_yaml19.parse)(raw);
20746
+ data = (0, import_yaml20.parse)(raw);
19615
20747
  } catch (e) {
19616
20748
  return { teams: [], problem: `${rel} can't be read: ${e.message.split("\n")[0]}` };
19617
20749
  }
@@ -19669,7 +20801,7 @@ function ownerWords(o) {
19669
20801
  }
19670
20802
 
19671
20803
  // packages/core/dist/question-proposals.js
19672
- var import_yaml20 = __toESM(require_dist(), 1);
20804
+ var import_yaml21 = __toESM(require_dist(), 1);
19673
20805
  import { readdir as readdir9, readFile as readFile12, realpath, stat as stat3 } from "node:fs/promises";
19674
20806
  import { isAbsolute as isAbsolute2, join as join13, relative as relative3 } from "node:path";
19675
20807
  var QUESTION_PROPOSAL_SCHEMA_VERSION = 1;
@@ -19708,7 +20840,7 @@ async function listedRepos(root) {
19708
20840
  continue;
19709
20841
  let data;
19710
20842
  try {
19711
- data = (0, import_yaml20.parse)(text4);
20843
+ data = (0, import_yaml21.parse)(text4);
19712
20844
  } catch {
19713
20845
  continue;
19714
20846
  }
@@ -19723,7 +20855,7 @@ async function listedRepos(root) {
19723
20855
  }
19724
20856
  return ids;
19725
20857
  }
19726
- function under(base, path) {
20858
+ function under2(base, path) {
19727
20859
  const r = relative3(base, path);
19728
20860
  if (!r || isAbsolute2(r) || r.split(/[\\/]/)[0] === "..")
19729
20861
  return void 0;
@@ -19761,7 +20893,7 @@ async function checkProposal(root, q2, p2) {
19761
20893
  }
19762
20894
  const realBase = await realpath(base);
19763
20895
  const real = await realpath(join13(base, ...rel.split("/"))).catch(() => void 0);
19764
- const realRel = real === void 0 ? void 0 : under(realBase, real);
20896
+ const realRel = real === void 0 ? void 0 : under2(realBase, real);
19765
20897
  if (real !== void 0 && realRel === void 0) {
19766
20898
  problems.push(`${rel} leaves the repo: cite a file in it.`);
19767
20899
  continue;
@@ -19809,7 +20941,7 @@ async function checkOne(root, id) {
19809
20941
  return { id, file, ok: false, problems: [] };
19810
20942
  let data;
19811
20943
  try {
19812
- data = (0, import_yaml20.parse)(raw);
20944
+ data = (0, import_yaml21.parse)(raw);
19813
20945
  } catch (e) {
19814
20946
  return {
19815
20947
  id,
@@ -19933,7 +21065,7 @@ function descriptionWords(d) {
19933
21065
  }
19934
21066
 
19935
21067
  // packages/core/dist/setup-edit.js
19936
- var import_yaml21 = __toESM(require_dist(), 1);
21068
+ var import_yaml22 = __toESM(require_dist(), 1);
19937
21069
  import { createHash as createHash9 } from "node:crypto";
19938
21070
  import { mkdir as mkdir3, readdir as readdir10, readFile as readFile13 } from "node:fs/promises";
19939
21071
  import { dirname, isAbsolute as isAbsolute3, join as join14, normalize, sep as sep3 } from "node:path";
@@ -19975,7 +21107,7 @@ var SetupEditError = class extends Error {
19975
21107
  var issues = (e) => e.issues.map((i) => `${i.path.join(".") || "the file"}: ${i.message}`).join("; ");
19976
21108
  var packRel = (root, rel) => `${isAdopted(root) ? ".atticus/org-pack" : "org-pack"}/${rel}`;
19977
21109
  function yamlDoc(text4, where2) {
19978
- const doc = (0, import_yaml21.parseDocument)(lfOnly(text4));
21110
+ const doc = (0, import_yaml22.parseDocument)(lfOnly(text4));
19979
21111
  if (doc.errors.length)
19980
21112
  throw new SetupEditError("invalid", `${where2} isn't YAML: ${doc.errors[0].message}`);
19981
21113
  return doc;
@@ -20002,10 +21134,10 @@ async function setRuntimeAdapter(root, kind, value, o = {}) {
20002
21134
  if (o.baseSha256 !== void 0 && sha256Of(before) !== o.baseSha256)
20003
21135
  throw new SetupEditError("exists", `${packRel(root, "runtime.yaml")} changed since this form read it (another window, the raw editor or the CLI): read it again, then make the edit.`);
20004
21136
  const doc = yamlDoc(before, "runtime.yaml");
20005
- if (!(0, import_yaml21.isMap)(doc.contents))
21137
+ if (!(0, import_yaml22.isMap)(doc.contents))
20006
21138
  throw new SetupEditError("invalid", "runtime.yaml isn't a map.");
20007
21139
  let adapters = doc.get("adapters");
20008
- if (!(0, import_yaml21.isMap)(adapters)) {
21140
+ if (!(0, import_yaml22.isMap)(adapters)) {
20009
21141
  doc.set("adapters", doc.createNode({}));
20010
21142
  adapters = doc.get("adapters");
20011
21143
  }
@@ -20017,26 +21149,26 @@ async function setRuntimeAdapter(root, kind, value, o = {}) {
20017
21149
  if (!map.items.length)
20018
21150
  map.flow = false;
20019
21151
  const entry = map.get(kind, true);
20020
- const had = (0, import_yaml21.isMap)(entry) ? entry.get("settings", true) : void 0;
21152
+ const had = (0, import_yaml22.isMap)(entry) ? entry.get("settings", true) : void 0;
20021
21153
  if (!Object.keys(settings).length)
20022
21154
  map.set(kind, value.type);
20023
- else if ((0, import_yaml21.isMap)(entry)) {
21155
+ else if ((0, import_yaml22.isMap)(entry)) {
20024
21156
  if (entry.get("type") !== value.type)
20025
21157
  entry.set("type", value.type);
20026
- if ((0, import_yaml21.isMap)(had)) {
21158
+ if ((0, import_yaml22.isMap)(had)) {
20027
21159
  for (const pair of [...had.items]) {
20028
- const k = (0, import_yaml21.isScalar)(pair.key) ? String(pair.key.value) : String(pair.key);
21160
+ const k = (0, import_yaml22.isScalar)(pair.key) ? String(pair.key.value) : String(pair.key);
20029
21161
  if (!(k in settings))
20030
21162
  had.delete(pair.key);
20031
21163
  }
20032
21164
  for (const [k, v] of Object.entries(settings)) {
20033
21165
  const now = had.get(k, true);
20034
- if (now !== void 0 && sameValue((0, import_yaml21.isNode)(now) ? now.toJS(doc) : now, v))
21166
+ if (now !== void 0 && sameValue((0, import_yaml22.isNode)(now) ? now.toJS(doc) : now, v))
20035
21167
  continue;
20036
- if ((0, import_yaml21.isScalar)(now) && !Array.isArray(v))
21168
+ if ((0, import_yaml22.isScalar)(now) && !Array.isArray(v))
20037
21169
  now.value = v;
20038
21170
  else
20039
- had.set(k, doc.createNode(v, { flow: (0, import_yaml21.isSeq)(now) && now.flow === true }));
21171
+ had.set(k, doc.createNode(v, { flow: (0, import_yaml22.isSeq)(now) && now.flow === true }));
20040
21172
  }
20041
21173
  } else
20042
21174
  entry.set("settings", doc.createNode(settings, { flow: false }));
@@ -20112,8 +21244,8 @@ async function idsUniqueAcrossProfiles(root, r, content) {
20112
21244
  if (orgPackFileSchema(r) !== RepoManifest)
20113
21245
  return;
20114
21246
  const mine = r.split("/")[1];
20115
- const repos = (0, import_yaml21.parseDocument)(lfOnly(content)).get("repos");
20116
- const ids = (0, import_yaml21.isSeq)(repos) ? repos.items.map((x) => (0, import_yaml21.isMap)(x) ? x.get("id") : void 0).filter((x) => typeof x === "string") : [];
21247
+ const repos = (0, import_yaml22.parseDocument)(lfOnly(content)).get("repos");
21248
+ const ids = (0, import_yaml22.isSeq)(repos) ? repos.items.map((x) => (0, import_yaml22.isMap)(x) ? x.get("id") : void 0).filter((x) => typeof x === "string") : [];
20117
21249
  const listed = /* @__PURE__ */ new Map();
20118
21250
  for (const other of await manifestFiles(root)) {
20119
21251
  if (other.platform === mine)
@@ -20121,11 +21253,11 @@ async function idsUniqueAcrossProfiles(root, r, content) {
20121
21253
  const t = await readFile13(other.path, "utf8").catch(() => void 0);
20122
21254
  if (t === void 0)
20123
21255
  continue;
20124
- const list = (0, import_yaml21.parseDocument)(lfOnly(t)).get("repos");
20125
- if (!(0, import_yaml21.isSeq)(list))
21256
+ const list = (0, import_yaml22.parseDocument)(lfOnly(t)).get("repos");
21257
+ if (!(0, import_yaml22.isSeq)(list))
20126
21258
  continue;
20127
21259
  for (const x of list.items) {
20128
- const id = (0, import_yaml21.isMap)(x) ? x.get("id") : void 0;
21260
+ const id = (0, import_yaml22.isMap)(x) ? x.get("id") : void 0;
20129
21261
  if (typeof id === "string" && !listed.has(id))
20130
21262
  listed.set(id, other.rel);
20131
21263
  }
@@ -20154,7 +21286,7 @@ function orgPackFileProblems(rel, content) {
20154
21286
  const r = orgPackFileRel(rel);
20155
21287
  if (!/\.ya?ml$/i.test(r))
20156
21288
  return [];
20157
- const doc = (0, import_yaml21.parseDocument)(lfOnly(content));
21289
+ const doc = (0, import_yaml22.parseDocument)(lfOnly(content));
20158
21290
  if (doc.errors.length)
20159
21291
  return doc.errors.map((e) => `${r} isn't YAML: ${e.message}`);
20160
21292
  const schema = orgPackFileSchema(r);
@@ -20196,11 +21328,11 @@ async function addPattern(root, p2, o = {}) {
20196
21328
  const there = await readFile13(join14(orgPackDirOf(root), "patterns", `${data.code}.yaml`), "utf8").then(() => true).catch(() => false);
20197
21329
  if (there)
20198
21330
  throw new SetupEditError("exists", `${packRel(root, rel)} is there already: edit it in the raw editor instead.`);
20199
- return finish2(root, rel, void 0, (0, import_yaml21.stringify)(data, { lineWidth: 0 }), o.preview);
21331
+ return finish2(root, rel, void 0, (0, import_yaml22.stringify)(data, { lineWidth: 0 }), o.preview);
20200
21332
  }
20201
21333
 
20202
21334
  // packages/core/dist/specs.js
20203
- var import_yaml22 = __toESM(require_dist(), 1);
21335
+ var import_yaml23 = __toESM(require_dist(), 1);
20204
21336
  import { createHash as createHash10 } from "node:crypto";
20205
21337
  import { readdir as readdir11, readFile as readFile14, rm } from "node:fs/promises";
20206
21338
  import { join as join15 } from "node:path";
@@ -20211,7 +21343,7 @@ var SPEC_CACHE_VERSION = `spec@${FLOW_SCHEMA_VERSION}.${SPEC_HEADER_SCHEMA_VERSI
20211
21343
  function parseSpecFile(text4, name, rel) {
20212
21344
  let data;
20213
21345
  try {
20214
- data = (0, import_yaml22.parse)(text4);
21346
+ data = (0, import_yaml23.parse)(text4);
20215
21347
  } catch (e) {
20216
21348
  return { ok: false, message: e.message.split("\n")[0] };
20217
21349
  }
@@ -20302,7 +21434,7 @@ ${toCanonicalYaml(h, HEADER_KEYS)}`);
20302
21434
  }
20303
21435
  async function readSpecFindings(root, repo) {
20304
21436
  try {
20305
- const r = SpecFindings.safeParse((0, import_yaml22.parse)(await readFile14(join15(specDirOf(root, repo), SPEC_FINDINGS_FILE), "utf8")));
21437
+ const r = SpecFindings.safeParse((0, import_yaml23.parse)(await readFile14(join15(specDirOf(root, repo), SPEC_FINDINGS_FILE), "utf8")));
20306
21438
  return r.success ? r.data : void 0;
20307
21439
  } catch {
20308
21440
  return void 0;
@@ -20329,7 +21461,7 @@ async function specRepos(root) {
20329
21461
  }
20330
21462
  async function readEstateJoins(root) {
20331
21463
  try {
20332
- const r = EstateJoins.safeParse((0, import_yaml22.parse)(await readFile14(join15(specsDirOf(root), ESTATE_FILE), "utf8")));
21464
+ const r = EstateJoins.safeParse((0, import_yaml23.parse)(await readFile14(join15(specsDirOf(root), ESTATE_FILE), "utf8")));
20333
21465
  return r.success ? r.data : void 0;
20334
21466
  } catch {
20335
21467
  return void 0;
@@ -20407,7 +21539,7 @@ var isAssistantResolution = (r, known = []) => !!r && assistantActor(r.by, known
20407
21539
 
20408
21540
  // packages/core/dist/link-candidates.js
20409
21541
  var JOINABLE = /* @__PURE__ */ new Set(["rest", "soap", "grpc", "graphql"]);
20410
- var PLACEHOLDER2 = /^(\$\{[^}]*\}|@[^@]+@|\{[^}]*\}|:[a-z_]\w*|\*\*?)$/i;
21542
+ var PLACEHOLDER = /^(\$\{[^}]*\}|@[^@]+@|\{[^}]*\}|:[a-z_]\w*|\*\*?)$/i;
20411
21543
  function resolvePath(p2, settings) {
20412
21544
  if (!settings)
20413
21545
  return { path: p2, resolved: false };
@@ -20421,12 +21553,12 @@ function resolvePath(p2, settings) {
20421
21553
  });
20422
21554
  return { path: out, resolved };
20423
21555
  }
20424
- var segs = (p2) => normalizePath(p2.replace(/\$\{[^}]*\}/g, "{}")).toLowerCase().split("/").filter(Boolean).filter((x, i) => !(i === 0 && /^v\d+$/.test(x)));
21556
+ var segs2 = (p2) => normalizePath(p2.replace(/\$\{[^}]*\}/g, "{}")).toLowerCase().split("/").filter(Boolean).filter((x, i) => !(i === 0 && /^v\d+$/.test(x)));
20425
21557
  var STOP = /* @__PURE__ */ new Set(["path", "url", "uri", "endpoint", "api", "v1", "v2", "v3", "the"]);
20426
21558
  function wordsOf(p2) {
20427
21559
  return new Set(p2.replace(/\$\{([^}]*)\}/g, " $1 ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").toLowerCase().split(/[^a-z0-9]+/).filter((w) => w.length > 1 && !STOP.has(w) && !/^\d+$/.test(w)).map((w) => w.endsWith("s") && w.length > 3 ? w.slice(0, -1) : w));
20428
21560
  }
20429
- var isWild = (s) => s === "{}" || PLACEHOLDER2.test(s);
21561
+ var isWild = (s) => s === "{}" || PLACEHOLDER.test(s);
20430
21562
  function pairScore(call, api, settings) {
20431
21563
  const tries = [pathScore2(call, api)];
20432
21564
  const r = resolvePath(call.path, settings);
@@ -20456,8 +21588,8 @@ function pairScore(call, api, settings) {
20456
21588
  var methodFactor = (call, api) => !!call.method && !!api.method && call.method.toUpperCase() !== api.method.toUpperCase() ? 0.5 : 1;
20457
21589
  function pathScore2(call, api) {
20458
21590
  const k = methodFactor(call, api);
20459
- const a = segs(call.path);
20460
- const b = segs(api.path);
21591
+ const a = segs2(call.path);
21592
+ const b = segs2(api.path);
20461
21593
  const eq = (x, y) => x === y || isWild(x) || isWild(y);
20462
21594
  const shaped = a.some((x) => !isWild(x)) && b.some((x) => !isWild(x));
20463
21595
  if (a.length && a.join("/") === b.join("/"))
@@ -20550,14 +21682,14 @@ function linkCandidates(o) {
20550
21682
  }
20551
21683
 
20552
21684
  // packages/core/dist/decision-batches.js
20553
- var import_yaml23 = __toESM(require_dist(), 1);
21685
+ var import_yaml24 = __toESM(require_dist(), 1);
20554
21686
  import { readdir as readdir12, readFile as readFile15 } from "node:fs/promises";
20555
21687
  import { join as join16 } from "node:path";
20556
21688
  var batchRelOf = (root, id) => `${decisionsRelOf(root)}/${id}.yaml`;
20557
21689
  async function writeBatch(root, b) {
20558
21690
  const p2 = DecisionBatch.parse(b);
20559
21691
  await writeFileAtomic(join16(decisionsDirOf(root), `${p2.id}.yaml`), `# A batch of decisions (ADR 0181): what it applied and what it took away. Undo: atticus questions undo ${p2.id}
20560
- ${(0, import_yaml23.stringify)(p2, { lineWidth: 0 })}`);
21692
+ ${(0, import_yaml24.stringify)(p2, { lineWidth: 0 })}`);
20561
21693
  return batchRelOf(root, p2.id);
20562
21694
  }
20563
21695
  async function readBatch(root, id) {
@@ -20566,7 +21698,7 @@ async function readBatch(root, id) {
20566
21698
  const text4 = await readFile15(join16(decisionsDirOf(root), `${id}.yaml`), "utf8").catch(() => void 0);
20567
21699
  if (text4 === void 0)
20568
21700
  return void 0;
20569
- const r = DecisionBatch.safeParse((0, import_yaml23.parse)(text4));
21701
+ const r = DecisionBatch.safeParse((0, import_yaml24.parse)(text4));
20570
21702
  return r.success ? r.data : void 0;
20571
21703
  }
20572
21704
  async function listBatches(root) {
@@ -20577,7 +21709,7 @@ async function listBatches(root) {
20577
21709
  const file = `${decisionsRelOf(root)}/${n}`;
20578
21710
  let data;
20579
21711
  try {
20580
- data = (0, import_yaml23.parse)(await readFile15(join16(decisionsDirOf(root), n), "utf8"));
21712
+ data = (0, import_yaml24.parse)(await readFile15(join16(decisionsDirOf(root), n), "utf8"));
20581
21713
  } catch (e) {
20582
21714
  problems.push({ file, message: `not YAML: ${e.message.split("\n")[0]}` });
20583
21715
  continue;
@@ -20635,7 +21767,7 @@ async function migrateOne(file, dryRun) {
20635
21767
  }
20636
21768
 
20637
21769
  // packages/core/dist/declared-links.js
20638
- var import_yaml24 = __toESM(require_dist(), 1);
21770
+ var import_yaml25 = __toESM(require_dist(), 1);
20639
21771
  import { readdir as readdir13, readFile as readFile16 } from "node:fs/promises";
20640
21772
  import { join as join17 } from "node:path";
20641
21773
  var DeclareError = class extends Error {
@@ -20661,12 +21793,12 @@ async function systemNode(root, system) {
20661
21793
  continue;
20662
21794
  const eol = eolOf(raw);
20663
21795
  const text4 = lfOnly(raw);
20664
- const doc = (0, import_yaml24.parseDocument)(text4);
21796
+ const doc = (0, import_yaml25.parseDocument)(text4);
20665
21797
  const seq = doc.get("systems");
20666
- if (!(0, import_yaml24.isSeq)(seq))
21798
+ if (!(0, import_yaml25.isSeq)(seq))
20667
21799
  continue;
20668
- const node = seq.items.find((x) => (0, import_yaml24.isMap)(x) && x.get("id") === system);
20669
- if ((0, import_yaml24.isMap)(node))
21800
+ const node = seq.items.find((x) => (0, import_yaml25.isMap)(x) && x.get("id") === system);
21801
+ if ((0, import_yaml25.isMap)(node))
20670
21802
  return { ...f, raw, text: text4, eol, doc, node };
20671
21803
  }
20672
21804
  return void 0;
@@ -20678,18 +21810,18 @@ async function declareLink(root, d, o) {
20678
21810
  if (!found)
20679
21811
  throw new DeclareError("not-found", `No system of the profiles is ${d.system}.`);
20680
21812
  const { path, rel, raw, text: text4, eol } = found;
20681
- const doc = (0, import_yaml24.parseDocument)(d.kind === "topic" ? migrateProfileText(text4).text : text4);
20682
- const node = doc.get("systems").items.find((x) => (0, import_yaml24.isMap)(x) && x.get("id") === d.system);
21813
+ const doc = (0, import_yaml25.parseDocument)(d.kind === "topic" ? migrateProfileText(text4).text : text4);
21814
+ const node = doc.get("systems").items.find((x) => (0, import_yaml25.isMap)(x) && x.get("id") === d.system);
20683
21815
  const field = d.kind === "topic" ? "topics" : "calls";
20684
21816
  let list = node.get(field);
20685
- if (!(0, import_yaml24.isSeq)(list)) {
21817
+ if (!(0, import_yaml25.isSeq)(list)) {
20686
21818
  node.set(field, doc.createNode([]));
20687
21819
  list = node.get(field);
20688
21820
  }
20689
- if (!(0, import_yaml24.isSeq)(list))
21821
+ if (!(0, import_yaml25.isSeq)(list))
20690
21822
  throw new DeclareError("invalid", `${rel}: ${d.system} has no ${field} list.`);
20691
21823
  const value = d.kind === "topic" ? d.topic.trim() : d.route.trim();
20692
- const has2 = list.items.some((x) => d.kind === "topic" ? (0, import_yaml24.isScalar)(x) && String(x.value) === value : (0, import_yaml24.isMap)(x) && x.get("route") === value);
21824
+ const has2 = list.items.some((x) => d.kind === "topic" ? (0, import_yaml25.isScalar)(x) && String(x.value) === value : (0, import_yaml25.isMap)(x) && x.get("route") === value);
20693
21825
  if (has2)
20694
21826
  throw new DeclareError("exists", `${rel} already has ${value} under ${d.system}'s ${field}.`);
20695
21827
  const item = d.kind === "topic" ? doc.createNode(value) : doc.createNode(DeclaredCall.parse({ route: value }));
@@ -20711,8 +21843,8 @@ async function undeclareLink(root, d) {
20711
21843
  throw new DeclareError("not-found", `No system of the profiles is ${d.system}.`);
20712
21844
  const { path, rel, raw, text: text4, eol, doc, node } = found;
20713
21845
  const list = node.get(d.kind === "topic" ? "topics" : "calls");
20714
- const i = (0, import_yaml24.isSeq)(list) ? list.items.findIndex((x) => COMMENT.test(x.comment ?? "") && (d.kind === "topic" ? (0, import_yaml24.isScalar)(x) && String(x.value) === d.value : (0, import_yaml24.isMap)(x) && x.get("route") === d.value)) : -1;
20715
- if (!(0, import_yaml24.isSeq)(list) || i < 0)
21846
+ const i = (0, import_yaml25.isSeq)(list) ? list.items.findIndex((x) => COMMENT.test(x.comment ?? "") && (d.kind === "topic" ? (0, import_yaml25.isScalar)(x) && String(x.value) === d.value : (0, import_yaml25.isMap)(x) && x.get("route") === d.value)) : -1;
21847
+ if (!(0, import_yaml25.isSeq)(list) || i < 0)
20716
21848
  throw new DeclareError("not-found", `${rel} has no ${d.value} declared from the canvas under ${d.system} (removed already, or written by hand there).`);
20717
21849
  list.items.splice(i, 1);
20718
21850
  const after = doc.toString({ lineWidth: 0, flowCollectionPadding: true });
@@ -20729,15 +21861,15 @@ async function declaredOf(root, system) {
20729
21861
  return m ? { ...m[1] ? { side: m[1] } : {}, by: m[2], at: m[3] } : {};
20730
21862
  };
20731
21863
  const topics = found.node.get("topics");
20732
- if ((0, import_yaml24.isSeq)(topics)) {
21864
+ if ((0, import_yaml25.isSeq)(topics)) {
20733
21865
  for (const x of topics.items)
20734
- if ((0, import_yaml24.isScalar)(x))
21866
+ if ((0, import_yaml25.isScalar)(x))
20735
21867
  out.push({ kind: "topic", system, value: String(x.value), ...read(x.comment) });
20736
21868
  }
20737
21869
  const calls = found.node.get("calls");
20738
- if ((0, import_yaml24.isSeq)(calls)) {
21870
+ if ((0, import_yaml25.isSeq)(calls)) {
20739
21871
  for (const x of calls.items)
20740
- if ((0, import_yaml24.isMap)(x) && typeof x.get("route") === "string")
21872
+ if ((0, import_yaml25.isMap)(x) && typeof x.get("route") === "string")
20741
21873
  out.push({ kind: "call", system, value: String(x.get("route")), ...read(x.comment) });
20742
21874
  }
20743
21875
  return { rel: found.rel, list: out };
@@ -20780,22 +21912,6 @@ var ReadingRulesFile = external_exports.strictObject({
20780
21912
  });
20781
21913
 
20782
21914
  export {
20783
- fieldKey,
20784
- lineNamesRoute,
20785
- lineNamesWord,
20786
- lineNamesField,
20787
- lineNamesClaim,
20788
- claimOnLines,
20789
- normalizeQuote,
20790
- quoteMatches,
20791
- isBinaryPath,
20792
- quoteNotRequired,
20793
- isSecretPath,
20794
- hasSecretShape,
20795
- redactSecrets,
20796
- quoteHoldsSecret,
20797
- partsBuildWord,
20798
- partsNamePath,
20799
21915
  FACT_KINDS,
20800
21916
  FactId,
20801
21917
  CitePart,
@@ -20911,6 +22027,7 @@ export {
20911
22027
  addManifestRepo,
20912
22028
  addManifestRepos,
20913
22029
  renameManifestRepo,
22030
+ renamedManifest,
20914
22031
  migrateManifests,
20915
22032
  eolOf,
20916
22033
  lfOnly,
@@ -21009,6 +22126,7 @@ export {
21009
22126
  joinFlagsOf,
21010
22127
  sharedLinkFlags,
21011
22128
  joinRecords,
22129
+ preferredEnvironment,
21012
22130
  joinVendorOperations,
21013
22131
  PROTOTYPE_TYPE,
21014
22132
  isPrototypeType,
@@ -21099,6 +22217,7 @@ export {
21099
22217
  parseAuditFile,
21100
22218
  serializeAuditFile,
21101
22219
  auditCandidates,
22220
+ seededShuffle,
21102
22221
  drawAudit,
21103
22222
  mergeDraw,
21104
22223
  wilson,
@@ -21106,6 +22225,34 @@ export {
21106
22225
  sumAuditPrecision,
21107
22226
  auditItemHolds,
21108
22227
  sampleConfirmed,
22228
+ canaryReportsRelOf,
22229
+ isCanaryRepoName,
22230
+ CANARY_READS_DIR,
22231
+ isCanaryMetarepoId,
22232
+ canaryRunPrefix,
22233
+ isCanaryRunName,
22234
+ canaryRunOf,
22235
+ CANARY_WHATS,
22236
+ CanaryPlanted,
22237
+ CanaryRemoved,
22238
+ CanarySkipped,
22239
+ CanaryKey,
22240
+ CanaryRate,
22241
+ CanaryReport,
22242
+ parseCanaryReport,
22243
+ serializeCanaryReport,
22244
+ foldCanary,
22245
+ canaryClaimText,
22246
+ canaryNeedleOf,
22247
+ plantedBy,
22248
+ removedMatch,
22249
+ removedBy,
22250
+ canaryRate,
22251
+ scoreCanary,
22252
+ canaryCovers,
22253
+ silentErrorRate,
22254
+ latestCanaries,
22255
+ isWindowsDeviceName,
21109
22256
  STACK_HELPERS,
21110
22257
  stackHelpersOff,
21111
22258
  helperOn,
@@ -21160,6 +22307,7 @@ export {
21160
22307
  MESH_KEY,
21161
22308
  referenceFields,
21162
22309
  recordReferences,
22310
+ byDecisionTime,
21163
22311
  applyCurated,
21164
22312
  mapAtOnce,
21165
22313
  readParsedFiles,
@@ -21227,6 +22375,8 @@ export {
21227
22375
  askedGapQuestionId,
21228
22376
  questionFromDraft,
21229
22377
  routeQuestion,
22378
+ questionFileOf,
22379
+ questionFileText,
21230
22380
  writeQuestion,
21231
22381
  readQuestion,
21232
22382
  listQuestions,