@maycombhq/atticus 2.0.0-beta.21 → 2.0.0-beta.23

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 (299) hide show
  1. package/dist/bin.js +12 -7
  2. package/dist/{chunk-BXBCMGIQ.js → chunk-24OXGB3P.js} +1 -1
  3. package/dist/{chunk-PRW3HXM3.js → chunk-27AJAKX7.js} +29 -5
  4. package/dist/{chunk-PQH56YF6.js → chunk-2QPJ4E4Z.js} +6 -4
  5. package/dist/{chunk-7CZHUZBL.js → chunk-2UMSHYCB.js} +38 -27
  6. package/dist/{chunk-2V2ZPQQU.js → chunk-2WUTCPPJ.js} +9 -7
  7. package/dist/{chunk-YF5DZCPN.js → chunk-2YSD6E6V.js} +38 -34
  8. package/dist/{chunk-QHJJMZLX.js → chunk-3424TLIJ.js} +204 -97
  9. package/dist/{chunk-62DLJSLV.js → chunk-3ASYYMOX.js} +10 -8
  10. package/dist/{chunk-XOL3GFW2.js → chunk-3EWKO457.js} +111 -43
  11. package/dist/{chunk-G5YJBNDZ.js → chunk-3EX5HCZD.js} +8 -6
  12. package/dist/{chunk-WFU77T3A.js → chunk-3MYBT62N.js} +5 -5
  13. package/dist/{chunk-6EXDI5GI.js → chunk-3UHV76UD.js} +72 -41
  14. package/dist/{chunk-LU4MQVAL.js → chunk-3ZA3AK2D.js} +11 -10
  15. package/dist/{chunk-P2VBXX7N.js → chunk-4ETO2FXE.js} +11 -9
  16. package/dist/{chunk-GK4PYVEC.js → chunk-4FLNCK6Q.js} +31 -14
  17. package/dist/{chunk-64AADMTW.js → chunk-4GAB5ZOZ.js} +943 -336
  18. package/dist/{chunk-FLVZFTLQ.js → chunk-4MYHETJ3.js} +20 -18
  19. package/dist/chunk-4R3TO4VL.js +94 -0
  20. package/dist/{chunk-7EFILTCI.js → chunk-5F7GFN2F.js} +28 -0
  21. package/dist/chunk-5MYE42AP.js +43 -0
  22. package/dist/chunk-5O7U67UA.js +57 -0
  23. package/dist/{chunk-MZGRDONP.js → chunk-5OXKCH4Z.js} +54 -37
  24. package/dist/{chunk-PUEWDYGP.js → chunk-5VTIWEWP.js} +3 -2
  25. package/dist/{chunk-3G6S7LAA.js → chunk-63NFFAGI.js} +14 -12
  26. package/dist/{chunk-LIJJCBQI.js → chunk-66AQ2JIU.js} +15 -16
  27. package/dist/chunk-6JVPBGQG.js +50 -0
  28. package/dist/{chunk-WAZEXEJH.js → chunk-6NCPLIIP.js} +167 -2
  29. package/dist/{chunk-D57MFJPP.js → chunk-6NN36LVK.js} +3 -3
  30. package/dist/{chunk-G6IQYM25.js → chunk-6R5VHR3N.js} +8 -6
  31. package/dist/{chunk-Z3QFH7YG.js → chunk-6RQOINER.js} +5 -4
  32. package/dist/{chunk-TQTRWENN.js → chunk-6RYB3EET.js} +14 -12
  33. package/dist/{chunk-FYBF5MB2.js → chunk-6SNTHK43.js} +13 -11
  34. package/dist/{chunk-FRHD22WM.js → chunk-6Y4FXOMI.js} +27 -23
  35. package/dist/{chunk-LWDNKE4X.js → chunk-6ZFF7XSL.js} +6 -6
  36. package/dist/{chunk-FQ6WH6PB.js → chunk-6ZSYLZ7O.js} +6 -4
  37. package/dist/{chunk-LQH4P45K.js → chunk-73CC73I4.js} +1 -1
  38. package/dist/{chunk-Q46QDDMF.js → chunk-73GFVW2L.js} +14 -9
  39. package/dist/{chunk-QKMRFNMA.js → chunk-73V2OONC.js} +17 -15
  40. package/dist/{chunk-FVMPFCDS.js → chunk-75OMRKY2.js} +4 -4
  41. package/dist/{chunk-XEQCQO66.js → chunk-7IFTSAHP.js} +10 -8
  42. package/dist/{chunk-4FOAYLI4.js → chunk-7K5OH45X.js} +139 -17
  43. package/dist/{chunk-3SSTNB4E.js → chunk-7NQAGYK4.js} +34 -14
  44. package/dist/{chunk-URIKUID7.js → chunk-7XWJ6ED2.js} +14 -12
  45. package/dist/{chunk-TYD6I4CZ.js → chunk-7XYLNQFO.js} +7 -7
  46. package/dist/{chunk-BPPU3PW7.js → chunk-7YQBDE5W.js} +10 -4
  47. package/dist/{chunk-CPK7QSBG.js → chunk-A4JXVO5O.js} +8 -6
  48. package/dist/{chunk-YJ3TBOTK.js → chunk-AFBCNZRZ.js} +29 -26
  49. package/dist/{chunk-TW3KOSQK.js → chunk-AGOLEMHK.js} +13 -13
  50. package/dist/chunk-AHFQHPFF.js +49 -0
  51. package/dist/{chunk-NTAVOWYD.js → chunk-APDN6UOR.js} +118 -18
  52. package/dist/chunk-AQRUQNFB.js +322 -0
  53. package/dist/{chunk-KYZMRSPS.js → chunk-AVMWESFZ.js} +6 -3
  54. package/dist/chunk-B4AEL3RF.js +1011 -0
  55. package/dist/{chunk-GS76RXQE.js → chunk-BAY4K55I.js} +15 -12
  56. package/dist/{chunk-4CLK2RJO.js → chunk-BFL4PO64.js} +9 -7
  57. package/dist/{chunk-GCS3FZOB.js → chunk-BFMTGNAQ.js} +15 -4
  58. package/dist/{chunk-YBOVNMHC.js → chunk-BP33TBLI.js} +29 -16
  59. package/dist/chunk-BQGDB6ZL.js +7342 -0
  60. package/dist/{chunk-BXZ4PKIT.js → chunk-BUUJ7N4O.js} +15 -11
  61. package/dist/{chunk-HGHRSF3E.js → chunk-BYBU2EIB.js} +38 -19
  62. package/dist/{chunk-TQ4TG57V.js → chunk-C6ORPLCN.js} +4 -4
  63. package/dist/{chunk-HWD4JPU7.js → chunk-CA3DKO4D.js} +27 -3
  64. package/dist/{chunk-YTTNTQOX.js → chunk-CFUDAW3R.js} +17 -15
  65. package/dist/{chunk-OPQZISG3.js → chunk-CJEBRJBS.js} +5 -4
  66. package/dist/{chunk-RALY3E5U.js → chunk-CKVBDVIW.js} +6 -4
  67. package/dist/{chunk-DUPZPDCJ.js → chunk-CMB7FXHJ.js} +42 -16
  68. package/dist/{chunk-YIGBJNH4.js → chunk-CQ7RF4QN.js} +5 -4
  69. package/dist/{chunk-YAH5IQAL.js → chunk-CS4BMJLL.js} +6 -5
  70. package/dist/{chunk-455SYIIE.js → chunk-CT6NINGR.js} +5 -3
  71. package/dist/chunk-CXTG6AWM.js +40 -0
  72. package/dist/{chunk-JYMIB5XY.js → chunk-CZ2ZS7AT.js} +170 -45
  73. package/dist/{chunk-K332XW7K.js → chunk-D6BVLTDV.js} +100 -33
  74. package/dist/chunk-DCRYOMTM.js +37 -0
  75. package/dist/{chunk-G6X4YL4D.js → chunk-DHKDH464.js} +5 -4
  76. package/dist/{chunk-JRVNXLZP.js → chunk-DSHRA72L.js} +14 -12
  77. package/dist/{chunk-LNWEWYCM.js → chunk-E3PDCQRH.js} +2813 -621
  78. package/dist/chunk-EHXDB3SA.js +25 -0
  79. package/dist/{chunk-EZIN5E5B.js → chunk-EMVZIOOD.js} +11 -9
  80. package/dist/{chunk-IFHDV6KQ.js → chunk-ENH6Z4TY.js} +21 -20
  81. package/dist/{chunk-YKTE2RU3.js → chunk-EVTI22PQ.js} +7 -2
  82. package/dist/{chunk-2D7PWSOK.js → chunk-EXJZBL5N.js} +22 -20
  83. package/dist/{chunk-77O633L5.js → chunk-FBCVC2GJ.js} +14 -12
  84. package/dist/{chunk-HS4BGB4G.js → chunk-FJVUHQPS.js} +37 -24
  85. package/dist/{chunk-4KNOJC6J.js → chunk-FL344WQD.js} +270 -221
  86. package/dist/{chunk-GNWAOVFQ.js → chunk-FMJYKLDY.js} +5 -5
  87. package/dist/chunk-FMR2D3AZ.js +41 -0
  88. package/dist/{chunk-PAINMSID.js → chunk-FPBUTZI5.js} +3102 -7859
  89. package/dist/{chunk-ZOSD4FXV.js → chunk-FQVSLBTV.js} +3 -3
  90. package/dist/chunk-FRAEQVYN.js +52 -0
  91. package/dist/{chunk-UDXWIPCB.js → chunk-FRCOKUU4.js} +9 -7
  92. package/dist/{chunk-UYLBRRFK.js → chunk-FSN6JFXB.js} +129 -27
  93. package/dist/{chunk-BC6KKZ67.js → chunk-FTLYXMHA.js} +9 -6
  94. package/dist/{chunk-FAJDKNSD.js → chunk-FVYZ4Y52.js} +16 -3
  95. package/dist/{chunk-TWQRPM76.js → chunk-G6EFXTUO.js} +23 -16
  96. package/dist/{chunk-ZFQMMU5Y.js → chunk-G7VBMOZH.js} +6 -2
  97. package/dist/{chunk-VYOCPTUB.js → chunk-GM4EFHUX.js} +17 -15
  98. package/dist/chunk-GOZLTLRY.js +232 -0
  99. package/dist/chunk-GPNMSX5H.js +36 -0
  100. package/dist/{chunk-OZJ3JLYI.js → chunk-GUGQSIQM.js} +10 -9
  101. package/dist/chunk-H4VO6WG3.js +10 -0
  102. package/dist/{chunk-QJCJOMW3.js → chunk-HJQVUOUL.js} +16 -18
  103. package/dist/chunk-HMWJWYE2.js +31 -0
  104. package/dist/{chunk-4TKVU2I2.js → chunk-HMZ2DRBC.js} +2 -2
  105. package/dist/{chunk-HK3VOHIE.js → chunk-HRS5O7VV.js} +609 -171
  106. package/dist/{chunk-7FUIVIBG.js → chunk-HUGQZQ2K.js} +13 -8
  107. package/dist/{chunk-QOOEYDNJ.js → chunk-ICBGVVRI.js} +10 -10
  108. package/dist/{chunk-XG4WJHLQ.js → chunk-IGOE6KPG.js} +49 -20
  109. package/dist/{chunk-4SLBCEPD.js → chunk-IKAW2KJU.js} +95 -64
  110. package/dist/{chunk-L4CESDPB.js → chunk-IMZFOMVX.js} +1 -1
  111. package/dist/{chunk-XQ3YZ4QW.js → chunk-ISG547IS.js} +24 -22
  112. package/dist/{chunk-BA2HUMDN.js → chunk-IYNCSYU4.js} +5 -2
  113. package/dist/{chunk-UEVZZZU2.js → chunk-J25YOUIZ.js} +5 -4
  114. package/dist/chunk-J2CDBSFP.js +69 -0
  115. package/dist/chunk-J2H7YG3K.js +34 -0
  116. package/dist/{chunk-O4IKAIZ2.js → chunk-J32IPTVQ.js} +28 -22
  117. package/dist/{chunk-3AQ2R5NL.js → chunk-J4CPHJUL.js} +11 -9
  118. package/dist/{chunk-VUVGX5L2.js → chunk-JFFKHIM6.js} +1 -1
  119. package/dist/chunk-JMEWJPF2.js +384 -0
  120. package/dist/{chunk-LO3BLMVG.js → chunk-JSP73CDW.js} +13 -5
  121. package/dist/chunk-JXAKYP45.js +63 -0
  122. package/dist/{chunk-PNQLCRSS.js → chunk-K4OXYSGS.js} +7 -5
  123. package/dist/{chunk-3J5I7ZOU.js → chunk-K4RNVDR4.js} +4 -4
  124. package/dist/{chunk-LEBR5NHW.js → chunk-K757G7AD.js} +18 -15
  125. package/dist/{chunk-AHW3RY3X.js → chunk-KDJ2YKAZ.js} +8 -7
  126. package/dist/{chunk-4WXRPQDE.js → chunk-KT6Q44CA.js} +178 -31
  127. package/dist/{chunk-EFCQSMXB.js → chunk-KTNOBTV5.js} +10 -4
  128. package/dist/chunk-KVVNAUIG.js +66 -0
  129. package/dist/{chunk-26Z7OGQW.js → chunk-L3RCQWVQ.js} +64 -31
  130. package/dist/{chunk-3WON4G3M.js → chunk-LHH5KG5A.js} +21 -6
  131. package/dist/{chunk-NCB6656Z.js → chunk-LM45GMMB.js} +11 -8
  132. package/dist/{chunk-2HH3UCZM.js → chunk-LO6Y7OTG.js} +5 -4
  133. package/dist/{chunk-36RY7ZXM.js → chunk-LPDTDFKA.js} +88 -26
  134. package/dist/{chunk-67BP7HXL.js → chunk-LSHSDC6S.js} +19 -17
  135. package/dist/{chunk-GDZB57IU.js → chunk-LZVHP7CT.js} +7 -5
  136. package/dist/{chunk-GC2VK3JT.js → chunk-M3EOFSPY.js} +28 -25
  137. package/dist/chunk-MBYYQHPM.js +31 -0
  138. package/dist/{chunk-HXXP2NTE.js → chunk-MEJ63LDG.js} +35 -12
  139. package/dist/{chunk-2UCRFXFZ.js → chunk-MH2ZK67S.js} +13 -11
  140. package/dist/{chunk-BEPCKDCP.js → chunk-MLGWSBF4.js} +5447 -4165
  141. package/dist/{chunk-NRQ65LTQ.js → chunk-MNIPPBCT.js} +6 -5
  142. package/dist/{chunk-3LZ6P5EP.js → chunk-MUWDB4R4.js} +1 -1
  143. package/dist/{chunk-KDAHXQIE.js → chunk-MWF4PXQR.js} +38 -34
  144. package/dist/{chunk-WNTIOBOG.js → chunk-N2YX6JMY.js} +20 -18
  145. package/dist/{chunk-FY3QIRTL.js → chunk-NAPHHWW2.js} +3 -3
  146. package/dist/{chunk-D2WSW4GU.js → chunk-NC755EKE.js} +8 -2
  147. package/dist/{chunk-BA3U7ALS.js → chunk-NCLZJCXA.js} +26 -22
  148. package/dist/chunk-NKJDO4UC.js +39 -0
  149. package/dist/chunk-NOYOFYAJ.js +59 -0
  150. package/dist/{chunk-LPV6T362.js → chunk-NROSSWMS.js} +8 -6
  151. package/dist/{chunk-ZKYRDV7A.js → chunk-OBUB3H72.js} +14 -12
  152. package/dist/{chunk-ZQLRCA2V.js → chunk-OCQWSFJD.js} +10 -8
  153. package/dist/{chunk-42EPP7OB.js → chunk-OK6JGLE7.js} +14 -12
  154. package/dist/{chunk-MD7KUEJ3.js → chunk-OPWGPQ2N.js} +9 -7
  155. package/dist/{chunk-SH27FYPF.js → chunk-OSYHGGL3.js} +20 -18
  156. package/dist/chunk-OXXZZ7HQ.js +50 -0
  157. package/dist/chunk-P22EPEBR.js +57 -0
  158. package/dist/chunk-P4YUT7W7.js +45 -0
  159. package/dist/chunk-PCCLVIDP.js +217 -0
  160. package/dist/chunk-PFULMC2D.js +48 -0
  161. package/dist/chunk-PGAMTKBI.js +16 -0
  162. package/dist/{chunk-Y6K3CJBU.js → chunk-PNSSE7JM.js} +152 -29
  163. package/dist/{chunk-3UTYPHN3.js → chunk-POEMZECG.js} +1 -1
  164. package/dist/{chunk-GSGIZ2OO.js → chunk-POSDBRKV.js} +27 -24
  165. package/dist/{chunk-YZDZOEV4.js → chunk-POSZFDSQ.js} +3 -3
  166. package/dist/{chunk-7AB6OWTV.js → chunk-PQQKZPBU.js} +31 -25
  167. package/dist/{chunk-K6JB6XTX.js → chunk-PRMUQUWN.js} +20 -15
  168. package/dist/{chunk-ICHDSWEY.js → chunk-PT4USJNN.js} +10 -8
  169. package/dist/{chunk-265LWMOA.js → chunk-PWXB5GBB.js} +18 -16
  170. package/dist/{chunk-DCWN3HFV.js → chunk-PXMV2LLY.js} +6 -5
  171. package/dist/{chunk-THN26IEF.js → chunk-PXW2RZGQ.js} +4 -1
  172. package/dist/{chunk-CG6CULP6.js → chunk-Q367UGYN.js} +7 -5
  173. package/dist/chunk-QA4O2GGC.js +265 -0
  174. package/dist/{chunk-7FHNFCHK.js → chunk-QAVRDONY.js} +225 -375
  175. package/dist/{chunk-VAMHOHUU.js → chunk-QBMLBCQH.js} +16 -13
  176. package/dist/{chunk-WEOMJHPV.js → chunk-QLQIFJP3.js} +18 -15
  177. package/dist/{chunk-UZACEG2C.js → chunk-QLWDIKO4.js} +84 -27
  178. package/dist/{chunk-ZZFHLRQW.js → chunk-QVVGJVVX.js} +18 -16
  179. package/dist/{chunk-WIWTJMMR.js → chunk-QX4MAMUG.js} +23 -21
  180. package/dist/{chunk-JYTIHTIK.js → chunk-QZWRPQTI.js} +6 -6
  181. package/dist/{chunk-5WERBKLE.js → chunk-RCG5IAAT.js} +55 -227
  182. package/dist/chunk-RGZFOKVO.js +106 -0
  183. package/dist/{chunk-C7CEK3KW.js → chunk-RLZFL76D.js} +7 -5
  184. package/dist/{chunk-PTQ3ZALZ.js → chunk-RPQITJNX.js} +14 -12
  185. package/dist/{chunk-JS6WMC3J.js → chunk-RQQYEDAC.js} +10 -8
  186. package/dist/chunk-RQSLHZ7T.js +36 -0
  187. package/dist/{chunk-API5TOUB.js → chunk-RRQUQAXP.js} +1 -1
  188. package/dist/chunk-RYQ4JCFT.js +65 -0
  189. package/dist/chunk-S35DIFJH.js +38 -0
  190. package/dist/{chunk-YWAKDNMH.js → chunk-S5GSQPIN.js} +70 -19
  191. package/dist/chunk-S5XFO4GY.js +42 -0
  192. package/dist/chunk-S6LW2RRC.js +25 -0
  193. package/dist/{chunk-TSM6T6GQ.js → chunk-S6W3D5GS.js} +25 -23
  194. package/dist/{chunk-5PV7S2ZP.js → chunk-S7GUZ45I.js} +4 -3
  195. package/dist/{chunk-MMZUN7ZO.js → chunk-SCT4CEF7.js} +22 -20
  196. package/dist/{chunk-AOCWFA7T.js → chunk-SK5RVP7X.js} +8 -8
  197. package/dist/chunk-SRTUETF5.js +50 -0
  198. package/dist/{chunk-E57AOFYN.js → chunk-SVGGMBJI.js} +15 -13
  199. package/dist/{chunk-OV57AHCG.js → chunk-SWNKO4C4.js} +35 -26
  200. package/dist/chunk-SYP56T2D.js +65 -0
  201. package/dist/{chunk-5CMPVC3N.js → chunk-T33TPFGI.js} +25 -23
  202. package/dist/{chunk-Q26LDIUV.js → chunk-T3FNG2H2.js} +18 -15
  203. package/dist/{chunk-UFE36WJH.js → chunk-T6MAWL5P.js} +6 -4
  204. package/dist/{chunk-LN77DXBM.js → chunk-T6MX7WXM.js} +14 -11
  205. package/dist/{chunk-WCEF7H6L.js → chunk-T7IIEDA3.js} +10 -7
  206. package/dist/{chunk-2HTEMYTB.js → chunk-TABH4RBZ.js} +163 -84
  207. package/dist/{chunk-YO2PKTXT.js → chunk-TDSCKP3V.js} +5 -3
  208. package/dist/{chunk-BVWWPBKD.js → chunk-TMFMXQEN.js} +23 -21
  209. package/dist/{chunk-4B6BT75O.js → chunk-TNCF26JK.js} +83 -26
  210. package/dist/{chunk-75ASLHBT.js → chunk-TUM52SOE.js} +21 -15
  211. package/dist/{chunk-ZLS6PU2O.js → chunk-TV56QLLV.js} +4 -3
  212. package/dist/{chunk-JKIGL3XQ.js → chunk-TVQSXWWV.js} +36 -33
  213. package/dist/{chunk-OKUB6RJA.js → chunk-TXNSQ24G.js} +14 -11
  214. package/dist/{chunk-4CYTJ5TZ.js → chunk-UALE35WK.js} +4 -3
  215. package/dist/{chunk-CNU5Q2D5.js → chunk-UJF7PIMP.js} +35 -27
  216. package/dist/chunk-UMCDODBX.js +53 -0
  217. package/dist/{chunk-M6D2U3YM.js → chunk-UTPIFH4I.js} +4 -3
  218. package/dist/{chunk-COYN3UAN.js → chunk-V7PEHQZU.js} +95 -26
  219. package/dist/{chunk-U3NBK4EU.js → chunk-VJFXQISZ.js} +8 -8
  220. package/dist/chunk-VJZI6KFP.js +47 -0
  221. package/dist/{chunk-ECLXZWAG.js → chunk-VK7WYA64.js} +14 -12
  222. package/dist/{chunk-DDJPM5YX.js → chunk-VKTXFFOZ.js} +5 -3
  223. package/dist/{chunk-LIRVU3HW.js → chunk-VNIN7Q6Q.js} +32 -20
  224. package/dist/{chunk-7QPCGTPS.js → chunk-VRO7KSGL.js} +24 -21
  225. package/dist/{chunk-AZDITBCT.js → chunk-W3AZE7LN.js} +3 -3
  226. package/dist/chunk-W4TNCEI4.js +44 -0
  227. package/dist/{chunk-S2RY3BOD.js → chunk-W5VYJWOG.js} +31 -21
  228. package/dist/{chunk-X2CUXTWU.js → chunk-WF3RCZNO.js} +6 -6
  229. package/dist/{chunk-4D62IZII.js → chunk-WOMQQWTO.js} +7 -5
  230. package/dist/{chunk-UF4UHCIG.js → chunk-WXVTYLVH.js} +6 -4
  231. package/dist/{chunk-EDZ45WIR.js → chunk-WYGTSZHR.js} +18 -14
  232. package/dist/{chunk-HSZMPH5T.js → chunk-WZYM5M4U.js} +592 -133
  233. package/dist/chunk-X5ZHDSLU.js +49 -0
  234. package/dist/chunk-X7XVMYIL.js +5 -0
  235. package/dist/chunk-X7ZKNSK4.js +41 -0
  236. package/dist/{chunk-QE527XRY.js → chunk-XAPXKFIS.js} +26 -23
  237. package/dist/{chunk-HE3HRDNZ.js → chunk-XF6TSZW2.js} +2 -2
  238. package/dist/{chunk-GX74YWR7.js → chunk-XFDDJQT7.js} +16 -14
  239. package/dist/{chunk-5QUOPNLN.js → chunk-XGO74QWR.js} +4 -4
  240. package/dist/chunk-XLZAAAPX.js +43 -0
  241. package/dist/{chunk-NYOABJNK.js → chunk-XMUWPA56.js} +26 -24
  242. package/dist/{chunk-M4H2UG4R.js → chunk-XNFM6WUK.js} +19 -16
  243. package/dist/{chunk-TGVVUKTG.js → chunk-XOMEQVLK.js} +2 -2
  244. package/dist/{chunk-A2G72UI4.js → chunk-Y2H7X3VI.js} +7 -7
  245. package/dist/{chunk-37WE3LS2.js → chunk-Y5IE6YKD.js} +5 -3
  246. package/dist/{chunk-IFFRGC3N.js → chunk-YD3KTW4H.js} +14 -12
  247. package/dist/{chunk-75ZOZFGH.js → chunk-YDCOZOER.js} +20 -18
  248. package/dist/{chunk-6DQYZU2W.js → chunk-YERAAEO4.js} +20 -20
  249. package/dist/{chunk-J5AAZ6OJ.js → chunk-YHMPDIRG.js} +5 -4
  250. package/dist/{chunk-CNPY4NTZ.js → chunk-Z2D4P3R3.js} +15 -13
  251. package/dist/{chunk-E2VXBSIR.js → chunk-Z3H27OMV.js} +6 -4
  252. package/dist/{chunk-AE4P57KK.js → chunk-Z3RAFU5B.js} +17 -15
  253. package/dist/{chunk-RA33EYS4.js → chunk-ZENHDXRZ.js} +23 -17
  254. package/dist/{chunk-TJH2EUAZ.js → chunk-ZFHFC74B.js} +20 -18
  255. package/dist/{chunk-4PYC2UGC.js → chunk-ZGULQAPZ.js} +7 -4
  256. package/dist/{chunk-4SKZDI62.js → chunk-ZIUFM5HT.js} +3 -1
  257. package/dist/{chunk-JAABT3DA.js → chunk-ZJGCGKA4.js} +4 -3
  258. package/dist/{chunk-GIFMBCTW.js → chunk-ZLQEQR3D.js} +10 -8
  259. package/dist/{chunk-I2A3Z5AK.js → chunk-ZNHQGG7J.js} +7 -7
  260. package/dist/{chunk-5TDRBOAV.js → chunk-ZNTTW4IT.js} +7 -5
  261. package/dist/{chunk-ZX7235KR.js → chunk-ZR6J4QFQ.js} +44 -383
  262. package/dist/{chunk-F6H2RJ3N.js → chunk-ZSNOILL5.js} +1 -1
  263. package/dist/files.json +585 -509
  264. package/dist/packages/sdk/npm/index.js +1491 -110
  265. package/dist/packages/ui/dist/assets/{elk-api-CowTnhEJ.js → elk-api-DxfAMOJq.js} +2 -2
  266. package/dist/packages/ui/dist/assets/index-Buit9TfP.js +62 -0
  267. package/dist/packages/ui/dist/assets/index-Jyc9dFeZ.css +1 -0
  268. package/dist/packages/ui/dist/index.html +3 -2
  269. package/package.json +3 -3
  270. package/dist/chunk-26WBY34Y.js +0 -37
  271. package/dist/chunk-3TD6S4TC.js +0 -49
  272. package/dist/chunk-5G7ILBUG.js +0 -66
  273. package/dist/chunk-6FNAKCET.js +0 -38
  274. package/dist/chunk-AM6FP6JW.js +0 -43
  275. package/dist/chunk-CFH3QH26.js +0 -29
  276. package/dist/chunk-CLD4RVTA.js +0 -45
  277. package/dist/chunk-D5KV5PSK.js +0 -45
  278. package/dist/chunk-D5MASS4I.js +0 -48
  279. package/dist/chunk-DN4A2Q2O.js +0 -57
  280. package/dist/chunk-FGAGWYZB.js +0 -47
  281. package/dist/chunk-GUYL7RMK.js +0 -60
  282. package/dist/chunk-J2O4LFVI.js +0 -80
  283. package/dist/chunk-JITJP64K.js +0 -34
  284. package/dist/chunk-JRXHON4E.js +0 -41
  285. package/dist/chunk-JU4QNJSR.js +0 -62
  286. package/dist/chunk-N3RUGTGV.js +0 -39
  287. package/dist/chunk-ODMBPDDV.js +0 -298
  288. package/dist/chunk-OMPENNWY.js +0 -39
  289. package/dist/chunk-PKJAV25S.js +0 -43
  290. package/dist/chunk-PRTBPXYA.js +0 -50
  291. package/dist/chunk-PRZ7KMWL.js +0 -42
  292. package/dist/chunk-QSIDVFB7.js +0 -45
  293. package/dist/chunk-SB5GRUFM.js +0 -54
  294. package/dist/chunk-T74WQQGS.js +0 -40
  295. package/dist/chunk-X7EMBM5X.js +0 -34
  296. package/dist/chunk-Z6VLC5X4.js +0 -36
  297. package/dist/chunk-ZPDDEVQX.js +0 -47
  298. package/dist/packages/ui/dist/assets/index-Dw20IRhQ.css +0 -1
  299. package/dist/packages/ui/dist/assets/index-z2wv0d5d.js +0 -47
@@ -1273,16 +1273,24 @@ var MetarepoStamp = z4.strictObject({
1273
1273
  });
1274
1274
 
1275
1275
  // packages/core/dist/schema/question.js
1276
- var QUESTION_SCHEMA_VERSION = 5;
1276
+ var QUESTION_SCHEMA_VERSION = 6;
1277
1277
  var QuestionSchemaVersion = z5.union([
1278
1278
  z5.literal(1),
1279
1279
  z5.literal(2),
1280
1280
  z5.literal(3),
1281
1281
  z5.literal(4),
1282
+ z5.literal(5),
1282
1283
  z5.literal(QUESTION_SCHEMA_VERSION)
1283
1284
  ]).overwrite(() => QUESTION_SCHEMA_VERSION);
1284
1285
  var QUESTION_ROLES = ["product", "architecture", "analysis", "delivery"];
1285
1286
  var QuestionRole = z5.enum(QUESTION_ROLES);
1287
+ var QUESTION_ASKS = ["business", "design", "delivery"];
1288
+ var QuestionAsks = z5.enum(QUESTION_ASKS);
1289
+ var QuestionRouted = z5.strictObject({
1290
+ from: QuestionRole.optional(),
1291
+ by: z5.string().trim().min(1),
1292
+ at: IsoDateTime
1293
+ });
1286
1294
  var AI_RUNTIMES = ["copilot-acp", "hand-off"];
1287
1295
  var DECIDE_BARS = ["confident", "agrees-with-shapes", "person-rule"];
1288
1296
  var DecideBar = z5.enum(DECIDE_BARS);
@@ -1413,6 +1421,10 @@ var Question = z5.strictObject({
1413
1421
  * that raised it unless the question said otherwise. Left out where no stage owns it.
1414
1422
  */
1415
1423
  role: QuestionRole.optional(),
1424
+ /** Version 6 (ADR 0191): what the question asks, as the AI tagged it when it raised it. */
1425
+ asks: QuestionAsks.optional(),
1426
+ /** Version 6 (ADR 0191): a person re-routed it; `role` is the role they gave it. */
1427
+ routed: QuestionRouted.optional(),
1416
1428
  /**
1417
1429
  * Version 5 (ninth UX walk): a critic knowledge gap a person routed with Ask: who it is
1418
1430
  * asked of (a team or a person, the finding's owner unless they named another).
@@ -1491,6 +1503,12 @@ var QuestionDraft = z5.strictObject({
1491
1503
  * design stage asking the product owner what the brief meant). Left out, the stage's role.
1492
1504
  */
1493
1505
  role: QuestionRole.optional(),
1506
+ /**
1507
+ * ADR 0191: what the question asks (business, design or delivery). It decides the role that
1508
+ * owns it when `role` is left out, so a business question a design stage raises goes to the
1509
+ * product owner, not the architect.
1510
+ */
1511
+ asks: QuestionAsks.optional(),
1494
1512
  /**
1495
1513
  * The step's own reading (ADR 0117): this question is one already on file (same), or asks
1496
1514
  * part of one (narrower), with the words of the earlier question that say so. Atticus checks
@@ -1667,13 +1685,41 @@ function normalizePath(input) {
1667
1685
  const trimmed = input.trim();
1668
1686
  if (trimmed === "")
1669
1687
  return "";
1670
- const withoutQuery = trimmed.split(/[?#]/, 1)[0] ?? "";
1688
+ const withoutQuery = stripParamConstraints(trimmed).split(/[?#]/, 1)[0] ?? "";
1671
1689
  const isPath = withoutQuery.startsWith("/") || withoutQuery.includes("/");
1672
1690
  if (!isPath)
1673
1691
  return withoutQuery;
1674
1692
  const segments = withoutQuery.split("/").filter((s) => s.length > 0).map((s) => /^(\{[^}]*\}|:[^/]+|<[^>]+>|\$\{[^}]*\})$/.test(s) ? "{}" : s);
1675
1693
  return "/" + segments.join("/");
1676
1694
  }
1695
+ function stripParamConstraints(path) {
1696
+ let out = "";
1697
+ let i = 0;
1698
+ while (i < path.length) {
1699
+ const ch = path[i];
1700
+ if (ch !== "{") {
1701
+ out += ch;
1702
+ i++;
1703
+ continue;
1704
+ }
1705
+ let depth = 0;
1706
+ let j = i;
1707
+ for (; j < path.length; j++) {
1708
+ if (path[j] === "{")
1709
+ depth++;
1710
+ else if (path[j] === "}" && --depth === 0)
1711
+ break;
1712
+ }
1713
+ if (j >= path.length) {
1714
+ out += path.slice(i);
1715
+ break;
1716
+ }
1717
+ const inner = path.slice(i + 1, j);
1718
+ out += "{" + (/^[^:?=]*/.exec(inner)?.[0] ?? "") + "}";
1719
+ i = j + 1;
1720
+ }
1721
+ return out;
1722
+ }
1677
1723
  function interfaceId(from, to, method, path) {
1678
1724
  const key = [from, to, (method ?? "").toUpperCase(), normalizePath(path)].join("|");
1679
1725
  return "if-" + createHash("sha256").update(key, "utf8").digest("hex").slice(0, 16);
@@ -1769,6 +1815,17 @@ function flowIssues(f) {
1769
1815
  return issues;
1770
1816
  }
1771
1817
  function parseRecord(input) {
1818
+ const v = input?.schemaVersion;
1819
+ if (typeof v === "number" && Number.isInteger(v) && v > SCHEMA_VERSION)
1820
+ return {
1821
+ ok: false,
1822
+ issues: [
1823
+ {
1824
+ path: "schemaVersion",
1825
+ message: `written by a newer Atticus (record version ${v}); install it to read this record`
1826
+ }
1827
+ ]
1828
+ };
1772
1829
  const result = CatalogRecord.safeParse(input);
1773
1830
  if (!result.success) {
1774
1831
  return {
@@ -2551,7 +2608,7 @@ var Approver = z11.strictObject({
2551
2608
  groups: z11.array(z11.string().min(1)).default([]),
2552
2609
  people: z11.array(z11.string().min(1)).default([])
2553
2610
  }).refine((a) => a.roles.length + a.groups.length + a.people.length > 0, "name at least one role, group or person");
2554
- var ROLES_SCHEMA_VERSION = 2;
2611
+ var ROLES_SCHEMA_VERSION = 3;
2555
2612
  var TeamPerson = z11.string().min(1).max(100).regex(/^@?[A-Za-z0-9][A-Za-z0-9._-]*$/, "a person's Git handle, such as pat or pat.doe");
2556
2613
  var Team = z11.strictObject({
2557
2614
  /** The id a repo manifest's `owner` names, e.g. team-ledger. */
@@ -2559,12 +2616,16 @@ var Team = z11.strictObject({
2559
2616
  /** What people call it, e.g. Ledger team. */
2560
2617
  name: z11.string().min(1).optional(),
2561
2618
  /** The Git handles of the people on it. */
2562
- people: z11.array(TeamPerson).default([])
2619
+ people: z11.array(TeamPerson).default([]),
2620
+ /** Version 3 (ADR 0191): who on the team takes each role on its repos' changes. */
2621
+ roles: z11.record(RecordId, z11.array(TeamPerson).min(1)).optional()
2563
2622
  });
2564
2623
  var Roles = z11.strictObject({
2565
- schemaVersion: z11.union([V2, z11.literal(ROLES_SCHEMA_VERSION)]),
2624
+ schemaVersion: z11.union([V2, z11.literal(2), z11.literal(ROLES_SCHEMA_VERSION)]),
2566
2625
  /** Version 2 (ADR 0140): the teams repos are owned by, and who is on each. */
2567
2626
  teams: z11.array(Team).default([]),
2627
+ /** Version 3 (ADR 0191): the organisation's person for each role, when no team names one. */
2628
+ defaults: z11.record(RecordId, z11.array(TeamPerson).min(1)).optional(),
2568
2629
  /** Extra roles; each is based on a built-in role's view. */
2569
2630
  custom: z11.array(z11.strictObject({ id: RecordId, name: z11.string().min(1), basedOn: z11.enum(BUILT_IN_ROLES) })).default([]),
2570
2631
  /** Optional roles this organisation uses. Core roles are always on. */
@@ -2581,12 +2642,31 @@ var Roles = z11.strictObject({
2581
2642
  const known = /* @__PURE__ */ new Set([...BUILT_IN_ROLES, ...r.custom.map((c) => c.id)]);
2582
2643
  unique(r.custom, (c) => c.id, ctx, "custom");
2583
2644
  unique(r.teams, (t) => t.id, ctx, "teams");
2584
- if (r.teams.length && r.schemaVersion < ROLES_SCHEMA_VERSION)
2645
+ if (r.teams.length && r.schemaVersion < 2)
2585
2646
  ctx.addIssue({
2586
2647
  code: "custom",
2587
2648
  path: ["teams"],
2588
2649
  message: "teams needs schemaVersion 2: run atticus upgrade"
2589
2650
  });
2651
+ const named = [
2652
+ ...r.defaults ? [{ path: ["defaults"], roles: r.defaults }] : [],
2653
+ ...r.teams.flatMap((t, i) => t.roles ? [{ path: ["teams", i, "roles"], roles: t.roles }] : [])
2654
+ ];
2655
+ for (const n of named) {
2656
+ if (r.schemaVersion < ROLES_SCHEMA_VERSION)
2657
+ ctx.addIssue({
2658
+ code: "custom",
2659
+ path: n.path,
2660
+ message: "who takes each role needs schemaVersion 3: run atticus upgrade"
2661
+ });
2662
+ for (const role of Object.keys(n.roles))
2663
+ if (!known.has(role))
2664
+ ctx.addIssue({
2665
+ code: "custom",
2666
+ path: [...n.path, role],
2667
+ message: `unknown role ${role}`
2668
+ });
2669
+ }
2590
2670
  r.custom.forEach((c, i) => {
2591
2671
  if (BUILT_IN_ROLES.includes(c.id)) {
2592
2672
  ctx.addIssue({
@@ -2771,6 +2851,27 @@ var IntegrationPattern = z11.strictObject({
2771
2851
  version: Semver,
2772
2852
  status: z11.enum(["confirmed", "to-review", "deprecated"])
2773
2853
  });
2854
+ function gitRefProblem(ref2) {
2855
+ if (!ref2)
2856
+ return "it is empty";
2857
+ if (ref2.startsWith("-"))
2858
+ return "it starts with -";
2859
+ if (/[\x00-\x20\x7f]/.test(ref2))
2860
+ return "it has a space or a control character";
2861
+ if (/[~^:?*[\\]/.test(ref2))
2862
+ return "it has one of ~ ^ : ? * [ \\";
2863
+ if (ref2.includes(".."))
2864
+ return "it has ..";
2865
+ if (ref2.includes("@{") || ref2 === "@")
2866
+ return "it is @ or has @{";
2867
+ if (ref2.startsWith("/") || ref2.endsWith("/") || ref2.includes("//"))
2868
+ return "it starts or ends with /, or has //";
2869
+ if (ref2.endsWith("."))
2870
+ return "it ends with .";
2871
+ if (ref2.split("/").some((c) => c.startsWith(".") || c.endsWith(".lock")))
2872
+ return "a part of it starts with . or ends with .lock";
2873
+ return void 0;
2874
+ }
2774
2875
  var RelPath = z11.string().min(1).refine((p2) => !p2.startsWith("/") && !/^[A-Za-z]:/.test(p2) && !p2.includes("\\") && !p2.split("/").includes(".."), "a relative path inside the metarepo");
2775
2876
  var SourceTags = z11.strictObject({
2776
2877
  kinds: z11.array(RecordId).default([]),
@@ -2849,7 +2950,11 @@ var Sources = z11.strictObject({
2849
2950
  /** What the source is about (ADR 0083), to guide the knowledge scan and filter items. */
2850
2951
  tags: SourceTags.optional(),
2851
2952
  /** A git wiki's branch or tag; default its default branch. A name git takes as a ref, never as an option. */
2852
- ref: z11.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/, "a branch or tag name").optional(),
2953
+ ref: z11.string().max(200).superRefine((r, ctx) => {
2954
+ const why = gitRefProblem(r);
2955
+ if (why)
2956
+ ctx.addIssue({ code: "custom", message: `a branch or tag name: ${why}` });
2957
+ }).optional(),
2853
2958
  /** The folder of a git wiki its pages are in; default the whole repository. */
2854
2959
  path: RelPath.optional(),
2855
2960
  /** A git wiki is cloned into local state (clone), or kept as a submodule of the metarepo under knowledge/repos/. */
@@ -2941,10 +3046,11 @@ var AdapterSettings = z11.record(z11.string(), z11.union([z11.string(), z11.numb
2941
3046
  }
2942
3047
  }
2943
3048
  });
2944
- var adapter = (types, o = {}) => z11.strictObject({
2945
- type: z11.enum([...types, "mock", ...o.manual === false ? [] : ["manual"]]),
2946
- settings: AdapterSettings.default({})
2947
- });
3049
+ var adapter = (types, o = {}) => {
3050
+ const type = z11.enum([...types, "mock", ...o.manual === false ? [] : ["manual"]]);
3051
+ const full = z11.strictObject({ type, settings: AdapterSettings.default({}) });
3052
+ return z11.union([type.transform((t) => ({ type: t, settings: {} })), full]);
3053
+ };
2948
3054
  var BuildEngine = z11.enum(["speckit", "atticus"]);
2949
3055
  var Autonomy = z11.enum(["plan-only", "draft", "draft-and-pr"]);
2950
3056
  var RetrievalSettings = z11.strictObject({
@@ -3007,8 +3113,9 @@ var RuntimeFields = z11.strictObject({
3007
3113
  */
3008
3114
  modes: z11.strictObject({
3009
3115
  allowed: z11.array(ConfiguredMode).min(1),
3010
- default: ConfiguredMode
3011
- }).refine((m) => m.allowed.includes(m.default), "the default mode must be allowed").default({ allowed: ["hand-off"], default: "hand-off" }),
3116
+ /** Left out: the first mode `allowed` lists (review round 50). */
3117
+ default: ConfiguredMode.optional()
3118
+ }).refine((m) => m.default === void 0 || m.allowed.includes(m.default), "the default mode must be allowed").transform((m) => ({ allowed: m.allowed, default: m.default ?? m.allowed[0] })).default({ allowed: ["hand-off"], default: "hand-off" }),
3012
3119
  models: z11.strictObject({
3013
3120
  allowed: z11.array(z11.string().min(1)).default([]),
3014
3121
  /** A recommended model per task type, shown in the assistant's picker hints. */
@@ -3336,6 +3443,9 @@ var Profile = z11.strictObject({
3336
3443
  });
3337
3444
  });
3338
3445
 
3446
+ // packages/core/dist/metarepo.js
3447
+ var LAYOUT_PATH = Sources.shape.layout.unwrap().shape.catalog.unwrap().optional();
3448
+
3339
3449
  // packages/core/dist/roles-migrate.js
3340
3450
  import { isMap, parseDocument } from "yaml";
3341
3451
 
@@ -3745,6 +3855,13 @@ var AuditFile = z17.strictObject({
3745
3855
  items: z17.array(AuditItem)
3746
3856
  });
3747
3857
 
3858
+ // packages/core/dist/cite.js
3859
+ var SECRET_WORDS = "(?:password|passwd|pwd|secret|token|api[-_]?key|access[-_]?key|private[-_]?key|credentials?)";
3860
+ 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");
3861
+ var SETTER_LITERAL = new RegExp(`(\\b(?:set|with)[A-Za-z0-9_]*?${SECRET_WORDS}\\s*\\(\\s*)(["'\`])((?:(?!\\2)[^\\\\]|\\\\.)+)\\2`, "i");
3862
+ var KEY_BARE = new RegExp(`((?:\\bexport\\s+|--|[?&;])[A-Za-z0-9_.-]*?${SECRET_WORDS}\\s*=\\s*)([^\\s&;"'\`]+)`, "gi");
3863
+ var SECRET_IDENT = new RegExp(`[A-Za-z0-9_]*${SECRET_WORDS}[A-Za-z0-9_]*`, "i");
3864
+
3748
3865
  // packages/core/dist/json-schema.js
3749
3866
  import { z as z27 } from "zod";
3750
3867
 
@@ -5332,7 +5449,7 @@ var DEFAULT_ROLES = Roles.parse({
5332
5449
  ]
5333
5450
  });
5334
5451
  var DEFAULT_RUNTIME = Runtime.parse({
5335
- schemaVersion: 2,
5452
+ schemaVersion: RUNTIME_SCHEMA_VERSION,
5336
5453
  assistants: { allowed: ["copilot", "claude-code"], default: "copilot" }
5337
5454
  });
5338
5455
  var DEFAULT_SOURCES = Sources.parse({ schemaVersion: 1 });
@@ -5367,6 +5484,7 @@ import { parse as parse5 } from "yaml";
5367
5484
 
5368
5485
  // packages/core/dist/api.js
5369
5486
  import { z as z30 } from "zod";
5487
+ var NextStep = z30.object({ step: z30.literal("sync"), repos: z30.array(z30.string()) });
5370
5488
  var Problem = z30.object({
5371
5489
  type: z30.string(),
5372
5490
  title: z30.string(),
@@ -5375,7 +5493,9 @@ var Problem = z30.object({
5375
5493
  /** Field-level problems for 400s. */
5376
5494
  errors: z30.array(z30.object({ path: z30.string(), message: z30.string() })).optional(),
5377
5495
  /** For 403s on gated actions: who can act, e.g. "Needs an architect: R. Patel". */
5378
- needs: z30.object({ role: z30.string(), names: z30.array(z30.string()) }).optional()
5496
+ needs: z30.object({ role: z30.string(), names: z30.array(z30.string()) }).optional(),
5497
+ /** 3.9.0: what the app offers next, e.g. Sync the repos with no base clone here. */
5498
+ next: NextStep.optional()
5379
5499
  });
5380
5500
  var Kind3 = z30.enum(RECORD_KINDS);
5381
5501
  var CatalogRecord2 = z30.union(RECORD_KINDS.map((k) => RECORD_SCHEMAS[k]));
@@ -5602,9 +5722,11 @@ var Coverage = z30.object({
5602
5722
  var JobState = z30.enum(["queued", "running", "done", "failed", "cancelled"]);
5603
5723
  var Job = z30.object({
5604
5724
  id: z30.string(),
5605
- kind: z30.enum(["scan", "sync", "reconcile", "index", "intake", "step", "local"]),
5725
+ kind: z30.enum(["scan", "sync", "reconcile", "index", "intake", "step", "local", "work"]),
5606
5726
  state: JobState,
5607
5727
  progress: z30.object({ done: z30.number().int(), total: z30.number().int(), message: z30.string() }),
5728
+ /** 3.1.0 (ADR 0187): what the job is, in words, for the Console. */
5729
+ title: z30.string().optional(),
5608
5730
  startedAt: z30.string(),
5609
5731
  finishedAt: z30.string().optional(),
5610
5732
  errors: z30.array(z30.string()),
@@ -5649,7 +5771,12 @@ var ChangeSummary = z30.object({
5649
5771
  }),
5650
5772
  updatedAt: z30.string(),
5651
5773
  /** ADR 0113: it takes the fast path, one step from brief to tasks (its type is small, or its brief says so). */
5652
- fastPath: z30.boolean().optional()
5774
+ fastPath: z30.boolean().optional(),
5775
+ /**
5776
+ * 3.9.0 (beta.23 review): the viewer's roles on the change, from its owners (any case, the
5777
+ * words people write for a role, roles.yaml's custom roles); empty when it names them nowhere.
5778
+ */
5779
+ yourRoles: z30.array(QuestionRole).optional()
5653
5780
  });
5654
5781
  var ChangeDetail = ChangeSummary.extend({
5655
5782
  /** 2.66.0 (review round 35): what a hand-off said, such as a branch it couldn't push. */
@@ -5662,7 +5789,13 @@ var ChangeDetail = ChangeSummary.extend({
5662
5789
  handoff: z30.object({
5663
5790
  phase: Phase,
5664
5791
  pr: z30.string().optional(),
5665
- state: z30.enum(["none", "open", "merged", "closed"])
5792
+ state: z30.enum(["none", "open", "merged", "closed"]),
5793
+ /**
5794
+ * 3.3.0 (app-only audit): the open hand-off's branch is here but not on the remote as it is
5795
+ * here (its push failed); POST .../handoff/push is Push again. Absent once it is there.
5796
+ */
5797
+ unpushed: z30.boolean().optional(),
5798
+ branch: z30.string().optional()
5666
5799
  }).optional()
5667
5800
  });
5668
5801
  var ArtifactContent = z30.object({
@@ -5718,7 +5851,16 @@ var Task = z30.object({
5718
5851
  * dependencies, and the earlier tasks of its own repo in tasks.md order); `sameRepo` names the
5719
5852
  * ones of its own repo. Absent when it waits for none, or once it is done.
5720
5853
  */
5721
- waits: z30.object({ tasks: z30.array(z30.string()), sameRepo: z30.array(z30.string()) }).optional()
5854
+ waits: z30.object({ tasks: z30.array(z30.string()), sameRepo: z30.array(z30.string()) }).optional(),
5855
+ /**
5856
+ * 3.3.0 (app-only audit): the task branch has commits the change branch here hasn't, so its
5857
+ * code isn't in the change yet (its PR raised and merged takes it in). Absent when it has none.
5858
+ */
5859
+ unmerged: z30.object({ commits: z30.number().int().positive(), branch: z30.string() }).optional(),
5860
+ /** 3.3.0: a person decided the task's work isn't needed in the change, and why. */
5861
+ decision: z30.object({ by: z30.string(), at: z30.string(), reason: z30.string() }).optional(),
5862
+ /** 3.3.0: whether the task's repo has a build command now (repos.manifest.yaml). */
5863
+ repoBuilds: z30.boolean().optional()
5722
5864
  });
5723
5865
  var RunView = RunSummary.extend({
5724
5866
  /**
@@ -5759,10 +5901,17 @@ var RunListItem = RunView.extend({
5759
5901
  toolCalls: z30.number().int().min(0).optional()
5760
5902
  });
5761
5903
  var StartStepRequest = z30.object({ args: z30.array(z30.string().min(1)).min(2) });
5904
+ var RunDoneRequest = z30.strictObject({ job: z30.boolean().optional() });
5762
5905
  var RunDoneView = RunView.extend({
5763
5906
  lines: z30.array(z30.string()).optional(),
5764
- next: z30.string().optional()
5765
- });
5907
+ next: z30.string().optional(),
5908
+ /** 3.5.0 (ADR 0188): the repo a read's last batch put on the map (verify --write). */
5909
+ applied: z30.string().optional()
5910
+ });
5911
+ var TaskContextView = z30.object({ markdown: z30.string() });
5912
+ var HistoryRecordingRequest = z30.object({ on: z30.boolean() });
5913
+ var HistoryRecordingView = z30.object({ on: z30.boolean() });
5914
+ var PruneRequest = z30.object({ change: z30.string().optional() });
5766
5915
  var PreparedStepView = z30.object({
5767
5916
  /** Left out when the step had nothing left to hand off: its lines say what it did. */
5768
5917
  runId: z30.string().optional(),
@@ -6123,7 +6272,20 @@ var ChangeKnowledgeItem = z30.object({
6123
6272
  tasks: z30.array(z30.string()).optional(),
6124
6273
  /** 2.30.0 (ADR 0132): the source of the page it is read from, and how much its word counts. */
6125
6274
  source: z30.string().optional(),
6126
- authority: z30.enum(SOURCE_AUTHORITIES).optional()
6275
+ authority: z30.enum(SOURCE_AUTHORITIES).optional(),
6276
+ /**
6277
+ * 3.6.0 (ADR 0191): what it says, to open it in place: a section's own text with its page and
6278
+ * heading, or an item's quote with its page. Left out when the page can't be read.
6279
+ */
6280
+ passage: z30.object({
6281
+ source: z30.string(),
6282
+ page: z30.string(),
6283
+ path: z30.string(),
6284
+ heading: z30.string(),
6285
+ line: z30.number().int(),
6286
+ text: z30.string(),
6287
+ quote: z30.string().optional()
6288
+ }).optional()
6127
6289
  });
6128
6290
  var KnowledgeConflictView = z30.object({
6129
6291
  /** The items it is about and its pages, each sorted: the same key is never asked twice. */
@@ -6623,6 +6785,117 @@ var StageCommentResult = z30.object({
6623
6785
  commit: z30.string(),
6624
6786
  next: z30.object({ command: z30.string(), slash: z30.string() })
6625
6787
  });
6788
+ var THREAD_STAGES = ["proposal", "feature", "architecture", "stories", "small"];
6789
+ var ThreadStage = z30.enum(THREAD_STAGES);
6790
+ var ThreadRunDetails = z30.object({
6791
+ agent: z30.string(),
6792
+ runtime: z30.string(),
6793
+ promptPath: z30.string(),
6794
+ output: z30.string().optional(),
6795
+ promptTokens: z30.number().int().min(0).optional(),
6796
+ model: z30.string().optional(),
6797
+ attempt: z30.number().int().min(1)
6798
+ });
6799
+ var ThreadItem = z30.discriminatedUnion("kind", [
6800
+ /** A prompt handed to the assistant (the stage's drafter, or the critic's lenses). */
6801
+ z30.object({
6802
+ kind: z30.literal("prompt"),
6803
+ at: z30.string(),
6804
+ runId: z30.string(),
6805
+ who: z30.enum(["drafter", "critic"]),
6806
+ prompt: z30.string(),
6807
+ state: RunState,
6808
+ details: ThreadRunDetails
6809
+ }),
6810
+ /** What came back, and what its checks said. */
6811
+ z30.object({
6812
+ kind: z30.literal("answer"),
6813
+ at: z30.string(),
6814
+ runId: z30.string(),
6815
+ who: z30.enum(["drafter", "critic"]),
6816
+ /** passed: the checks read it; failed: they found problems (listed); checking: not yet. */
6817
+ checked: z30.enum(["passed", "failed", "checking"]),
6818
+ /** Who checked it: the app when the file arrived (ADR 0189), or a person's Done. */
6819
+ by: z30.enum(["app", "person"]).optional(),
6820
+ summary: z30.array(z30.string()),
6821
+ problems: z30.array(z30.string())
6822
+ }),
6823
+ /** The files the stage wrote from an answer. */
6824
+ z30.object({ kind: z30.literal("changed"), at: z30.string(), files: z30.array(z30.string()) }),
6825
+ z30.object({
6826
+ kind: z30.literal("finding"),
6827
+ at: z30.string(),
6828
+ view: StageFindingView,
6829
+ /**
6830
+ * Whether the stage's assistant writes the file the finding cites: Fix then goes to it in the
6831
+ * next round; otherwise Fix opens the file at its line in the app's editor (`edit`).
6832
+ */
6833
+ assistantWrites: z30.boolean(),
6834
+ edit: z30.object({
6835
+ artifact: z30.string(),
6836
+ file: z30.string().optional(),
6837
+ line: z30.number().int().optional()
6838
+ }).optional()
6839
+ }),
6840
+ z30.object({ kind: z30.literal("question"), at: z30.string(), question: Question }),
6841
+ z30.object({
6842
+ kind: z30.literal("reply"),
6843
+ at: z30.string(),
6844
+ text: z30.string(),
6845
+ by: z30.string(),
6846
+ /** A round of the stage has read it. */
6847
+ read: z30.boolean(),
6848
+ /** The finding it is about, for a comment on one. */
6849
+ about: z30.string().optional()
6850
+ }),
6851
+ z30.object({
6852
+ kind: z30.literal("correction"),
6853
+ at: z30.string(),
6854
+ text: z30.string(),
6855
+ label: z30.string(),
6856
+ by: z30.string(),
6857
+ state: z30.string()
6858
+ }),
6859
+ /** A question the assistant raised that couldn't be kept: its evidence was no line. */
6860
+ z30.object({
6861
+ kind: z30.literal("dropped"),
6862
+ at: z30.string(),
6863
+ key: z30.string(),
6864
+ question: z30.string(),
6865
+ evidence: z30.array(z30.string()),
6866
+ nearest: z30.string().optional()
6867
+ }),
6868
+ z30.object({ kind: z30.literal("note"), at: z30.string(), text: z30.string() })
6869
+ ]);
6870
+ var StageThreadView = z30.object({
6871
+ change: z30.string(),
6872
+ stage: ThreadStage,
6873
+ /** Where the stage is, in one word, and the one sentence the thread opens with. */
6874
+ state: z30.enum(["not-started", "waiting", "questions", "drafting", "stopped", "done"]),
6875
+ headline: z30.string(),
6876
+ items: z30.array(ThreadItem),
6877
+ /** The run waiting for the assistant's answer, if one does. */
6878
+ waiting: z30.object({ runId: z30.string(), prompt: z30.string() }).optional(),
6879
+ /** The step's words, for POST /api/runs/handoff (the next round's prompt). */
6880
+ step: z30.array(z30.string()),
6881
+ /** Whether a reply is taken now, and if not, why. */
6882
+ reply: z30.object({ open: z30.boolean(), why: z30.string().optional() }),
6883
+ problems: z30.array(z30.object({ file: z30.string(), message: z30.string() }))
6884
+ });
6885
+ var StageThreadPost = z30.discriminatedUnion("kind", [
6886
+ z30.strictObject({ kind: z30.literal("reply"), text: z30.string().trim().min(1).max(4e3) }),
6887
+ z30.strictObject({
6888
+ kind: z30.literal("finding"),
6889
+ finding: z30.string().min(1),
6890
+ gate: z30.string().optional(),
6891
+ text: z30.string().trim().min(1).max(4e3)
6892
+ }),
6893
+ z30.strictObject({ kind: z30.literal("keep"), key: z30.string().regex(/^[0-9a-f]{12}$/) })
6894
+ ]);
6895
+ var StageThreadPostResult = z30.object({
6896
+ files: z30.array(z30.string()),
6897
+ thread: StageThreadView
6898
+ });
6626
6899
  var DRAFT_PAGES = ["feature", "architecture", "stories", "tasks"];
6627
6900
  var DraftPage = z30.enum(DRAFT_PAGES);
6628
6901
  var DraftProvenance = z30.object({
@@ -7060,14 +7333,25 @@ var Health = z30.object({
7060
7333
  openspec: z30.string().optional(),
7061
7334
  user: z30.string(),
7062
7335
  /** 2.22.0: started with `atticus ui --full`, so the app offers every page, not only the six. */
7063
- full: z30.boolean().optional()
7336
+ full: z30.boolean().optional(),
7337
+ /**
7338
+ * 3.5.0 (ADR 0190): whether the folder the app runs in is a metarepo (org-pack/, or
7339
+ * .atticus/org-pack/). When it isn't, the app offers Create the metarepo here.
7340
+ */
7341
+ metarepo: z30.boolean().optional()
7064
7342
  });
7065
7343
  var ScanRequest = z30.strictObject({
7066
7344
  repos: z30.array(RecordId).optional(),
7067
7345
  /** Ignore the cache and rescan everything. */
7068
7346
  full: z30.boolean().default(false),
7069
7347
  /** Another branch, scanned beside the baseline into catalog/branches/<branch>/ (ADR 0123). */
7070
- ref: GitRef.optional()
7348
+ ref: GitRef.optional(),
7349
+ /**
7350
+ * 3.3.0 (app-only audit): the app's scan is a cross-check with the built-in readers, and asks
7351
+ * which repo answers on an unknown host only for the repos the assistant has read (facts on
7352
+ * file); `askAll` asks for every repo, as the command line's `atticus scan` does.
7353
+ */
7354
+ askAll: z30.boolean().optional()
7071
7355
  });
7072
7356
  var RepoBranchesView = z30.object({
7073
7357
  id: RecordId,
@@ -7155,6 +7439,8 @@ var ChangeCockpit = z30.object({
7155
7439
  */
7156
7440
  openQuestionsByRole: z30.partialRecord(QuestionRole, z30.number().int()).optional(),
7157
7441
  yourRoles: z30.array(QuestionRole).optional(),
7442
+ /** 3.6.0 (ADR 0191): who the change waits on now, by role and name. */
7443
+ waitsOn: z30.lazy(() => WaitsOn).optional(),
7158
7444
  repos: z30.array(z30.object({ id: z30.string(), branch: z30.string(), base: z30.string(), pr: z30.string().optional() }))
7159
7445
  });
7160
7446
  var NewChangeRequest = z30.strictObject({
@@ -7205,13 +7491,48 @@ var ProposePlanView = z30.object({
7205
7491
  */
7206
7492
  applyFirst: z30.array(z30.string()).optional()
7207
7493
  });
7494
+ var CONFIRMED_WRITES = [
7495
+ "handoff",
7496
+ "release-prs",
7497
+ "merge",
7498
+ "task-pr",
7499
+ "digest-send",
7500
+ "propose",
7501
+ "step-run",
7502
+ "ai-model",
7503
+ "ai-test",
7504
+ // 3.6.0 (ADR 0191): the plan's work items in a live work tracker, and an owner question sent.
7505
+ "work-items",
7506
+ "owner-ask"
7507
+ ];
7508
+ var ConfirmedWrite = z30.enum(CONFIRMED_WRITES);
7509
+ var Confirmation = z30.string().regex(/^[A-Za-z0-9_-]{16,128}$/, "a confirmation");
7510
+ var ConfirmationRequest = z30.strictObject({
7511
+ write: ConfirmedWrite,
7512
+ /**
7513
+ * What the write is for: the change, `<change>/<task>`, the step, the scope, the digest's
7514
+ * channel (3.1.0; `me` before) or `model`.
7515
+ */
7516
+ target: z30.string().min(1).max(400),
7517
+ /** The page's own key, from its <meta name="atticus-page-key">; never printed. */
7518
+ pageKey: z30.string().max(200).optional()
7519
+ });
7520
+ var ConfirmationView = z30.object({
7521
+ confirmation: Confirmation,
7522
+ write: ConfirmedWrite,
7523
+ target: z30.string(),
7524
+ expiresAt: z30.string()
7525
+ });
7526
+ var ConfirmedRequest = z30.strictObject({ confirmation: Confirmation.optional() });
7208
7527
  var ProposeRequest = z30.strictObject({
7209
7528
  scope: ProposeScope,
7210
7529
  /** Exactly the files the person saw listed; one that changed back since is left out. */
7211
7530
  files: z30.array(z30.string().min(1)).min(1),
7212
7531
  title: z30.string().max(200).optional(),
7213
7532
  /** The branch GET's plan showed, so the PR is on the branch the person saw. */
7214
- branch: z30.string().max(200).optional()
7533
+ branch: z30.string().max(200).optional(),
7534
+ /** 3.0.0 (ADR 0186): the person's confirmation from the app (`propose`, the scope). */
7535
+ confirmation: Confirmation.optional()
7215
7536
  });
7216
7537
  var LinesView = z30.object({
7217
7538
  code: z30.number().int().optional(),
@@ -7446,11 +7767,30 @@ var FindingActionRequest = z30.strictObject({
7446
7767
  var OpenWorkspaceRequest = z30.strictObject({ repos: z30.array(RecordId).min(1) });
7447
7768
  var HandoffRequest = z30.strictObject({
7448
7769
  phase: Phase.optional(),
7449
- repo: z30.string().optional()
7770
+ repo: z30.string().optional(),
7771
+ /** 3.0.0 (ADR 0186): the person's confirmation from the app (`handoff`, the change). */
7772
+ confirmation: Confirmation.optional()
7773
+ });
7774
+ var SyncRequest = z30.strictObject({
7775
+ repo: z30.string().optional(),
7776
+ confirmation: Confirmation.optional()
7777
+ });
7778
+ var ReleasePrsRequest = z30.strictObject({ confirmation: Confirmation.optional() });
7779
+ var TaskDoneRequest = z30.strictObject({
7780
+ done: z30.boolean(),
7781
+ /**
7782
+ * 3.3.0 (app-only audit): why the task's work isn't needed, when its branch has commits the
7783
+ * change branch hasn't (else marking it done is 409); recorded with the person's name.
7784
+ */
7785
+ reason: z30.string().max(2e3).optional()
7786
+ });
7787
+ var UpstreamRequest = z30.strictObject({
7788
+ upstream: z30.string().regex(/^[A-Za-z0-9][\w.-]*\/[\w./-]+$/, "a remote branch, such as origin/main")
7789
+ });
7790
+ var TaskBuildRequest = z30.strictObject({
7791
+ raise: z30.boolean().optional(),
7792
+ confirmation: Confirmation.optional()
7450
7793
  });
7451
- var SyncRequest = z30.strictObject({ repo: z30.string().optional() });
7452
- var ReleasePrsRequest = z30.strictObject({});
7453
- var TaskDoneRequest = z30.strictObject({ done: z30.boolean() });
7454
7794
  var CHANGE_OWNER_ROLES = [
7455
7795
  "product-owner",
7456
7796
  "architect",
@@ -7507,7 +7847,9 @@ var StepRunRequest = z30.strictObject({
7507
7847
  with: z30.string().min(1),
7508
7848
  inputsSha256: z30.string().regex(/^[0-9a-f]{64}$/, "the sha-256 the preview showed"),
7509
7849
  fillOnly: z30.boolean().optional(),
7510
- change: z30.string().optional()
7850
+ change: z30.string().optional(),
7851
+ /** 3.0.0 (ADR 0186): the person's confirmation from the app (`step-run`, the step). */
7852
+ confirmation: Confirmation.optional()
7511
7853
  });
7512
7854
  var ArchiveRequest = z30.strictObject({ rescan: z30.boolean().optional() });
7513
7855
  var DraftRequestsRequest = z30.strictObject({ force: z30.boolean().optional() });
@@ -7550,7 +7892,10 @@ var SaveNotifyRequest = z30.strictObject({
7550
7892
  digest: z30.enum(["off", "daily", "weekly"]),
7551
7893
  channel: z30.string().trim().min(1).optional()
7552
7894
  });
7553
- var SendDigestRequest = z30.strictObject({ send: z30.boolean().default(false) });
7895
+ var SendDigestRequest = z30.strictObject({
7896
+ send: z30.boolean().default(false),
7897
+ confirmation: Confirmation.optional()
7898
+ });
7554
7899
  var TriageDecideRequest = z30.strictObject({
7555
7900
  option: z30.number().int().min(1),
7556
7901
  reason: z30.string().trim().min(1).optional()
@@ -7586,7 +7931,8 @@ var QuestionList = z30.object({
7586
7931
  problems: z30.array(z30.object({ file: z30.string(), message: z30.string() })),
7587
7932
  /**
7588
7933
  * 2.51.0: every question on file by state, whatever `state` or `mine` the list asked for, so a
7589
- * page shows its counts from the one request.
7934
+ * page shows its counts from the one request. With `change` they are that change's; with `role`
7935
+ * that role's, as the list is (`byRole` stays every role's).
7590
7936
  */
7591
7937
  counts: z30.object({
7592
7938
  open: z30.number().int(),
@@ -7630,6 +7976,8 @@ var QuestionList = z30.object({
7630
7976
  * the stage's that asked. Left out for a question no change's phase raised.
7631
7977
  */
7632
7978
  role: QuestionRole.optional(),
7979
+ /** 3.6.0 (ADR 0191): what it asks (business, design, delivery), its own or its role's. */
7980
+ asks: QuestionAsks.optional(),
7633
7981
  /**
7634
7982
  * 2.36.0 (ADR 0144, Q5): the answer the assistant proposed, for an open question, when
7635
7983
  * every line it cites says what it quotes. A person accepts it or answers otherwise.
@@ -8288,6 +8636,159 @@ var UpgradeView = z30.object({
8288
8636
  stamp: z30.string().optional(),
8289
8637
  pending: z30.array(z30.object({ id: z30.string(), summary: z30.string(), files: z30.array(z30.string()) }))
8290
8638
  });
8639
+ var FileEditView = z30.object({
8640
+ path: z30.string(),
8641
+ changes: z30.array(z30.object({ was: z30.string().optional(), now: z30.string().optional() })),
8642
+ written: z30.boolean(),
8643
+ note: z30.string(),
8644
+ /** The raw editor's runtime.yaml edit moves where the model's key goes: the write needs `ai-model`. */
8645
+ confirm: z30.literal("ai-model").optional()
8646
+ });
8647
+ var SetupMetarepoView = z30.object({
8648
+ metarepo: z30.boolean(),
8649
+ root: z30.string(),
8650
+ folder: z30.string(),
8651
+ suggested: z30.object({ name: z30.string(), platform: z30.string() }),
8652
+ /** The folder's origin, when it is a clone (without credentials). */
8653
+ origin: z30.string().optional(),
8654
+ /** The metarepo's id on the Git host, read from origin. */
8655
+ metarepoId: z30.string().optional()
8656
+ });
8657
+ var CreateMetarepoRequest = z30.strictObject({
8658
+ name: RecordId,
8659
+ platform: RecordId,
8660
+ owner: z30.string().trim().min(1).max(100).optional(),
8661
+ /** The metarepo's repo on the Git host, written under runtime.yaml's manual Git host. */
8662
+ metarepo: z30.string().trim().min(1).max(300).optional()
8663
+ });
8664
+ var OpenFolderRequest = z30.strictObject({ path: z30.string().min(1).max(4096) });
8665
+ var OpenFolderView = z30.object({
8666
+ url: z30.string(),
8667
+ root: z30.string(),
8668
+ metarepo: z30.boolean()
8669
+ });
8670
+ var ReposPlanRequest = z30.strictObject({
8671
+ urls: z30.string().max(2e5).optional(),
8672
+ dir: z30.string().min(1).max(4096).optional(),
8673
+ platform: RecordId.optional()
8674
+ }).refine((b) => !!b.urls?.trim() !== !!b.dir, "send urls or dir, one of them");
8675
+ var PlannedRepoView = z30.object({
8676
+ id: z30.string(),
8677
+ url: z30.string(),
8678
+ /** What the person gave, when the URL was normalised from it. */
8679
+ given: z30.string().optional(),
8680
+ type: z30.string(),
8681
+ defaultBranch: z30.string().optional(),
8682
+ /** The id it would have had, and why it got another (`-2`). */
8683
+ renamed: z30.object({ from: z30.string(), why: z30.string() }).optional(),
8684
+ detected: z30.object({ signals: z30.array(z30.string()), confidence: z30.string() }).optional()
8685
+ });
8686
+ var ReposPlanView = z30.object({
8687
+ platform: z30.string().optional(),
8688
+ platforms: z30.array(z30.string()),
8689
+ repos: z30.array(PlannedRepoView),
8690
+ /** Given, but a manifest lists that clone URL already: left out. */
8691
+ listed: z30.array(z30.object({ url: z30.string(), id: z30.string() })),
8692
+ refused: z30.array(z30.object({ given: z30.string(), why: z30.string() })),
8693
+ /** Folders repos discover looked at that aren't repos. */
8694
+ skipped: z30.array(z30.object({ path: z30.string(), reason: z30.string() }))
8695
+ });
8696
+ var AddReposRequest = z30.strictObject({
8697
+ platform: RecordId.optional(),
8698
+ repos: z30.array(z30.strictObject({
8699
+ id: RecordId,
8700
+ url: z30.string().min(1).max(2e3),
8701
+ type: z30.string().max(100).optional(),
8702
+ owner: z30.string().max(100).optional(),
8703
+ defaultBranch: z30.string().max(250).optional(),
8704
+ /** What it is, in the person's words (ADR 0128); optional. */
8705
+ description: z30.string().max(300).optional()
8706
+ })).min(1).max(500),
8707
+ preview: z30.boolean().optional()
8708
+ });
8709
+ var RepoTypeDetectView = z30.object({
8710
+ repo: z30.string(),
8711
+ /** The org pack's repo types (atticus repo-type detect), or the files as repo add reads them. */
8712
+ from: z30.enum(["repo-types", "files"]),
8713
+ verdict: z30.string(),
8714
+ /** The type to write, when the match settles one. */
8715
+ type: z30.string().optional(),
8716
+ signals: z30.array(z30.string()).optional(),
8717
+ confidence: z30.string().optional(),
8718
+ matches: z30.array(z30.object({ type: z30.string(), name: z30.string(), score: z30.number() }))
8719
+ });
8720
+ var RepoTypeRequest = z30.strictObject({
8721
+ type: z30.string().trim().min(1).max(100),
8722
+ preview: z30.boolean().optional()
8723
+ });
8724
+ var AdapterSettingValue = z30.union([z30.string(), z30.number(), z30.boolean(), z30.array(z30.string())]);
8725
+ var AdaptersView = z30.object({
8726
+ /** runtime.yaml, metarepo-relative. */
8727
+ path: z30.string(),
8728
+ /** 3.9.0: runtime.yaml's sha256 as read, sent back as a write's `baseSha256`. */
8729
+ sha256: z30.string(),
8730
+ kinds: z30.array(z30.object({
8731
+ kind: z30.string(),
8732
+ types: z30.array(z30.string()),
8733
+ /** The settings Atticus reads for this kind; a plugin may read more. */
8734
+ fields: z30.array(z30.object({ name: z30.string(), list: z30.boolean() })),
8735
+ current: z30.object({ type: z30.string(), settings: z30.record(z30.string(), AdapterSettingValue) }).nullable()
8736
+ })),
8737
+ problems: z30.array(z30.string())
8738
+ });
8739
+ var AdapterRequest = z30.strictObject({
8740
+ /** The adapter, or null to take it out of runtime.yaml. */
8741
+ value: z30.strictObject({
8742
+ type: z30.string().min(1).max(100),
8743
+ settings: z30.record(z30.string().max(100), AdapterSettingValue).optional()
8744
+ }).nullable(),
8745
+ /**
8746
+ * 3.9.0: runtime.yaml's sha256 as the form read it (AdaptersView's), so a write onto a file
8747
+ * changed since is refused (409), never overwriting the newer edit.
8748
+ */
8749
+ baseSha256: z30.string().regex(/^[0-9a-f]{64}$/).optional(),
8750
+ preview: z30.boolean().optional()
8751
+ });
8752
+ var OrgPackFileView = z30.object({
8753
+ path: z30.string(),
8754
+ /** Relative to the org pack folder. */
8755
+ rel: z30.string(),
8756
+ content: z30.string(),
8757
+ sha256: z30.string(),
8758
+ exists: z30.boolean(),
8759
+ /** Checked with its schema before it is written (a YAML file Atticus reads). */
8760
+ checked: z30.boolean()
8761
+ });
8762
+ var OrgPackFileRequest = z30.strictObject({
8763
+ path: z30.string().min(1).max(500),
8764
+ content: z30.string().max(2e6),
8765
+ /** The file's sha256 as opened (GET's), so an edit made meanwhile is refused. */
8766
+ baseSha256: z30.string().regex(/^[0-9a-f]{64}$/),
8767
+ preview: z30.boolean().optional(),
8768
+ confirmation: Confirmation.optional()
8769
+ });
8770
+ var PatternRequest = z30.strictObject({
8771
+ code: z30.string().min(1).max(60),
8772
+ name: z30.string().min(1).max(200),
8773
+ definition: z30.string().min(1).max(2e3),
8774
+ interaction: z30.string(),
8775
+ route: z30.string(),
8776
+ targetType: z30.string(),
8777
+ controls: z30.array(z30.string().max(200)).max(50).optional(),
8778
+ source: z30.string().min(1).max(500),
8779
+ version: z30.string().max(40).optional(),
8780
+ status: z30.string().optional(),
8781
+ preview: z30.boolean().optional()
8782
+ });
8783
+ var SourceRequest = z30.strictObject({
8784
+ type: z30.string().min(1).max(40),
8785
+ location: z30.string().min(1).max(2e3),
8786
+ id: RecordId.optional(),
8787
+ /** A git wiki's folder of pages, and its branch or tag. */
8788
+ path: z30.string().max(500).optional(),
8789
+ ref: z30.string().max(250).optional(),
8790
+ preview: z30.boolean().optional()
8791
+ });
8291
8792
  var ConnectLinksRequest = z30.object({
8292
8793
  from: z30.string().min(1),
8293
8794
  to: LinkBox,
@@ -8356,7 +8857,7 @@ var FileChangeResult = z30.object({
8356
8857
  commit: z30.string()
8357
8858
  });
8358
8859
  var SketchStrokeRequest = z30.object({
8359
- stroke: z30.object({ kind: z30.enum(["call", "topic", "table", "remove", "retarget", "undo"]) }).passthrough(),
8860
+ stroke: z30.object({ kind: z30.enum(["call", "topic", "table", "remove", "retarget", "undo", "retire"]) }).passthrough(),
8360
8861
  /** Say what it would write; write nothing. */
8361
8862
  preview: z30.boolean().optional(),
8362
8863
  /** The preview's fingerprint of the target flows: the write is refused (409) when they changed since. */
@@ -8538,8 +9039,102 @@ var CopilotRunCurrent = z30.object({
8538
9039
  why: z30.string().optional(),
8539
9040
  model: z30.string().optional()
8540
9041
  });
9042
+ var ActivityKind = z30.enum([
9043
+ // The app's own jobs (ADR 0015), by their kind.
9044
+ "scan",
9045
+ "sync",
9046
+ "reconcile",
9047
+ "index",
9048
+ "intake",
9049
+ "step",
9050
+ "local",
9051
+ /** A request the page waits on, run as a job (the critic, a wiki's sync, a step run, Done). */
9052
+ "work",
9053
+ /** An unattended Copilot run the app started (ADR 0173): its lines are its tabs. */
9054
+ "copilot",
9055
+ /** A command run in a terminal, by an editor or by a Copilot session. */
9056
+ "command",
9057
+ /** A hand-off run waiting for the person's assistant, and its Done. */
9058
+ "handoff"
9059
+ ]);
9060
+ var ActivityState = z30.enum([
9061
+ "running",
9062
+ "waiting",
9063
+ "done",
9064
+ "failed",
9065
+ "cancelled",
9066
+ /** Its process is gone and it never said how it ended (a terminal closed, a crash). */
9067
+ "ended"
9068
+ ]);
9069
+ var ActivityWhere = z30.enum([
9070
+ "app",
9071
+ "terminal",
9072
+ "vscode",
9073
+ "intellij",
9074
+ "copilot",
9075
+ /** A hand-off run: the person's own assistant does the work. */
9076
+ "assistant"
9077
+ ]);
9078
+ var ActivityEntry = z30.object({
9079
+ /** A job's id (job-N), a Copilot run's (copilot-run-...), term-<runId> for a command, a hand-off run's (run-...). */
9080
+ id: z30.string().min(1),
9081
+ kind: ActivityKind,
9082
+ /** What it is, in its own words: the command (`atticus map forge-ledger`), or the app's job. Left out for a job that gave none: the page names it by its kind. */
9083
+ title: z30.string().optional(),
9084
+ where: ActivityWhere,
9085
+ state: ActivityState,
9086
+ startedAt: z30.string(),
9087
+ finishedAt: z30.string().optional(),
9088
+ /** How far it is, when it says (a job's progress). */
9089
+ progress: z30.object({ done: z30.number().int(), total: z30.number().int(), message: z30.string() }).optional(),
9090
+ exitCode: z30.number().int().optional(),
9091
+ /** How many lines it has printed: the page asks for the ones it hasn't. */
9092
+ lines: z30.number().int().min(0),
9093
+ /** The first line still kept (older ones are dropped past the cap). */
9094
+ from: z30.number().int().min(0),
9095
+ /**
9096
+ * 3.9.0 (review of beta.23): which version of its lines these are, for an entry whose lines
9097
+ * are rewritten rather than only added to (a hand-off run's say what to do, then what Done
9098
+ * did). When it changes, the page reads its lines again from the start instead of adding.
9099
+ */
9100
+ rev: z30.string().optional(),
9101
+ /** The route that stops it (POST), when the app can; a command stops in its terminal. */
9102
+ stop: z30.string().optional(),
9103
+ jobId: z30.string().optional(),
9104
+ copilotRunId: z30.string().optional(),
9105
+ /** A command's run id (its files in .atticus/logs/). */
9106
+ runId: z30.string().optional(),
9107
+ /** A hand-off run: its change, where its prompt is and where the answer goes. */
9108
+ handoff: z30.object({
9109
+ runId: z30.string(),
9110
+ change: z30.string(),
9111
+ agent: z30.string().optional(),
9112
+ promptPath: z30.string(),
9113
+ output: z30.string().optional()
9114
+ }).optional()
9115
+ });
9116
+ var ActivityList = z30.object({
9117
+ /** Newest first. */
9118
+ entries: z30.array(ActivityEntry),
9119
+ /** How many are running now. */
9120
+ running: z30.number().int().min(0)
9121
+ });
9122
+ var ActivityLines = z30.object({
9123
+ id: z30.string(),
9124
+ /** The number of the first of these lines. */
9125
+ from: z30.number().int().min(0),
9126
+ lines: z30.array(z30.string()),
9127
+ /** How many lines it has printed in all. */
9128
+ total: z30.number().int().min(0),
9129
+ state: ActivityState
9130
+ });
8541
9131
  var LiveEvent = z30.discriminatedUnion("type", [
8542
- z30.object({ type: z30.literal("file.changed"), path: z30.string() }),
9132
+ z30.object({
9133
+ type: z30.literal("file.changed"),
9134
+ path: z30.string(),
9135
+ /** 3.9.0: whether it can change the catalog, by the folders the org pack's layout names. */
9136
+ catalog: z30.boolean().optional()
9137
+ }),
8543
9138
  z30.object({
8544
9139
  type: z30.literal("job.progress"),
8545
9140
  jobId: z30.string(),
@@ -8560,8 +9155,147 @@ var LiveEvent = z30.discriminatedUnion("type", [
8560
9155
  /** The number of the first of these lines in the tab. */
8561
9156
  at: z30.number().int().min(0),
8562
9157
  lines: z30.array(z30.string())
9158
+ }),
9159
+ // ADR 0187: an activity appeared or changed, and new lines one printed.
9160
+ z30.object({ type: z30.literal("activity.changed"), entry: ActivityEntry }),
9161
+ z30.object({
9162
+ type: z30.literal("activity.lines"),
9163
+ id: z30.string(),
9164
+ /** The number of the first of these lines. */
9165
+ at: z30.number().int().min(0),
9166
+ lines: z30.array(z30.string())
8563
9167
  })
8564
9168
  ]);
9169
+ var RouteQuestionRequest = z30.strictObject({ role: QuestionRole });
9170
+ var OwnerSuggestion = z30.object({
9171
+ role: z30.string(),
9172
+ people: z30.array(z30.string()),
9173
+ from: z30.union([
9174
+ z30.object({ team: z30.string(), name: z30.string().optional(), repos: z30.array(z30.string()) }),
9175
+ z30.object({ default: z30.literal(true) })
9176
+ ])
9177
+ });
9178
+ var OwnerSuggestionList = z30.object({
9179
+ change: z30.string(),
9180
+ suggestions: z30.array(OwnerSuggestion),
9181
+ /** Why there are none, in words, when there are none. */
9182
+ note: z30.string().optional()
9183
+ });
9184
+ var WaitsOn = z30.object({
9185
+ /** The change.yaml owner key: product-owner, architect, business-analyst or team-lead. */
9186
+ role: z30.string(),
9187
+ people: z30.array(z30.string()),
9188
+ /** `handoff`: its hand-off PR waits on their review; `phase`: the phase's work is theirs. */
9189
+ because: z30.enum(["handoff", "phase"]),
9190
+ phase: z30.string()
9191
+ });
9192
+ var FindingView = z30.strictObject({ ...Finding.shape, asks: QuestionAsks });
9193
+ var WorkItemPlan = z30.object({
9194
+ change: z30.string(),
9195
+ /** none: runtime.yaml names no work tracker; manual: steps for a person; live: the tracker. */
9196
+ tracker: z30.enum(["none", "manual", "live"]),
9197
+ items: z30.array(z30.object({
9198
+ key: z30.string(),
9199
+ type: z30.string(),
9200
+ title: z30.string(),
9201
+ action: z30.enum(["create", "update", "unchanged", "orphaned"]),
9202
+ /** The tracker's id once known; `manual:<step>` until a person records it. */
9203
+ id: z30.string().optional(),
9204
+ /** The step to record it on, for a manual id. */
9205
+ step: z30.string().optional(),
9206
+ /** The story it is under, for a task; the story's own key for a story. */
9207
+ story: z30.string().optional()
9208
+ })),
9209
+ /** The command that does the same in a terminal. */
9210
+ command: z30.string()
9211
+ });
9212
+ var WorkItemSyncRequest = z30.strictObject({
9213
+ confirmation: Confirmation.optional(),
9214
+ /** 3.9.0: run the sync as a job (202 and its id; the job's result `answer` is the result). */
9215
+ job: z30.boolean().optional()
9216
+ });
9217
+ var WorkItemSyncResult = z30.object({
9218
+ plan: WorkItemPlan,
9219
+ lines: z30.array(z30.string()),
9220
+ done: z30.array(z30.object({ key: z30.string(), action: z30.string(), id: z30.string() })),
9221
+ failed: z30.array(z30.object({ key: z30.string(), reason: z30.string() }))
9222
+ });
9223
+ var SendOwnerAskRequest = z30.strictObject({ confirmation: Confirmation.optional() });
9224
+ var SentOwnerAsk = z30.object({
9225
+ /** sent: through the adapter; step: a manual step for a person; not-sent: why in `why`. */
9226
+ state: z30.enum(["sent", "step", "not-sent"]),
9227
+ to: z30.string(),
9228
+ id: z30.string().optional(),
9229
+ why: z30.string().optional()
9230
+ });
9231
+ var KnowledgePassageView = z30.object({
9232
+ source: z30.string(),
9233
+ page: z30.string(),
9234
+ /** The page's root-relative path (the snapshot copy, or the inputs/ file). */
9235
+ path: z30.string(),
9236
+ heading: z30.string(),
9237
+ line: z30.number().int(),
9238
+ text: z30.string()
9239
+ });
9240
+ var KnowledgeAnswerView = z30.object({
9241
+ items: z30.array(z30.object({
9242
+ id: z30.string(),
9243
+ kind: z30.string(),
9244
+ title: z30.string(),
9245
+ quote: z30.object({
9246
+ source: z30.string(),
9247
+ page: z30.string(),
9248
+ section: z30.string().optional(),
9249
+ text: z30.string()
9250
+ }).optional()
9251
+ })),
9252
+ passages: z30.array(KnowledgePassageView),
9253
+ /** The AI step that answers from the items in words, citing them (atticus knowledge ask). */
9254
+ command: z30.string()
9255
+ });
9256
+ var StoryShapeOp = z30.enum(["rename", "split", "merge", "add"]);
9257
+ var StoryShapeRequest = z30.strictObject({
9258
+ op: StoryShapeOp,
9259
+ /** rename, split: the story; merge: the stories, the first keeps its number. */
9260
+ story: z30.string().optional(),
9261
+ stories: z30.array(z30.string()).min(2).optional(),
9262
+ /** rename, merge, add: its name; split: the first part's. */
9263
+ name: z30.string().trim().min(1).max(200),
9264
+ /** What the story is for, in the person's words (add, a split's parts). */
9265
+ words: z30.string().trim().max(2e3).optional(),
9266
+ /** split: the other parts, each a story of its own. */
9267
+ parts: z30.array(z30.strictObject({
9268
+ name: z30.string().trim().min(1).max(200),
9269
+ words: z30.string().trim().max(2e3).optional()
9270
+ })).optional()
9271
+ });
9272
+ var StoryShapeEntryView = z30.object({
9273
+ id: z30.string(),
9274
+ op: StoryShapeOp,
9275
+ story: z30.string().optional(),
9276
+ stories: z30.array(z30.string()).optional(),
9277
+ name: z30.string(),
9278
+ words: z30.string().optional(),
9279
+ parts: z30.array(z30.object({ id: z30.string(), name: z30.string(), words: z30.string().optional() })).optional(),
9280
+ /** The story an added one is. */
9281
+ added: z30.string().optional(),
9282
+ by: z30.string(),
9283
+ at: z30.string(),
9284
+ /** waiting: no draft has read it yet; applied: the stories now have it, with the run. */
9285
+ state: z30.enum(["waiting", "applied"]),
9286
+ run: z30.string().optional()
9287
+ });
9288
+ var StoryShapeView = z30.object({
9289
+ change: z30.string(),
9290
+ file: z30.string(),
9291
+ entries: z30.array(StoryShapeEntryView),
9292
+ /** Each task's story as the last draft mapped it, by task id. */
9293
+ assigned: z30.record(z30.string(), z30.string()),
9294
+ /** What the coverage check found: a story with no task, a task with no story. */
9295
+ uncovered: z30.array(z30.string()),
9296
+ /** The step that maps the tasks to the stories again. */
9297
+ command: z30.string()
9298
+ });
8565
9299
  var str3 = { type: "string" };
8566
9300
  var ref = (name) => ({ $ref: `#/components/schemas/${name}` });
8567
9301
  var arrayOf = (name) => ({ type: "array", items: ref(name) });
@@ -8592,10 +9326,20 @@ var OPS = {
8592
9326
  ok: { status: 200, schema: "Health", description: "OK" }
8593
9327
  }
8594
9328
  },
9329
+ "/api/confirmations": {
9330
+ post: {
9331
+ id: "confirmWrite",
9332
+ summary: "3.0.0 (ADR 0186): the app's page asks, on the person's click, for a confirmation of one write to a shared system (a hand-off, the release PRs, a merge, a task's PR, sending the digest, Propose for review, a step run with a team's tool, where the model's key goes, a Test of uncommitted model settings). It needs the page key the server puts in the page and never prints, so the session token alone gets 403; the confirmation is for that write and target, used once, and expires after two minutes",
9333
+ tag: "system",
9334
+ body: ConfirmationRequest,
9335
+ ok: { status: 201, schema: "ConfirmationView", description: "The confirmation" },
9336
+ errors: [400, 403]
9337
+ }
9338
+ },
8595
9339
  "/api/me": {
8596
9340
  get: {
8597
9341
  id: "getMe",
8598
- summary: "Who is using the app: the metarepo's Git user (handle, name, email, and a warning when the OS user stood in), what AI may do and the digest settings (ADR 0073)",
9342
+ summary: "Who is using the app: the metarepo's Git user (handle, name, email, and a warning when the OS user stood in), what AI may do and the digest settings (ADR 0073); 3.1.0: notify.to, where Send it to me posts",
8599
9343
  tag: "system",
8600
9344
  ok: {
8601
9345
  status: 200,
@@ -8627,7 +9371,7 @@ var OPS = {
8627
9371
  "/api/me/digest": {
8628
9372
  post: {
8629
9373
  id: "sendDigest",
8630
- summary: "What waits on the person; with send, posted through the notify adapter as their approval",
9374
+ summary: "What waits on the person; with send, posted through the notify adapter as their approval. 3.0.0 (ADR 0186): send needs the person's confirmation, else 403. 3.1.0 (review round 50): its target is the channel it posts to (GET /api/me's notify.to, read again at the send), not `me`",
8631
9375
  tag: "system",
8632
9376
  body: SendDigestRequest,
8633
9377
  ok: {
@@ -8635,7 +9379,7 @@ var OPS = {
8635
9379
  schema: { type: "object", required: ["title", "body", "lines"] },
8636
9380
  description: "The digest, with sent or notSent"
8637
9381
  },
8638
- errors: [400]
9382
+ errors: [400, 403]
8639
9383
  }
8640
9384
  },
8641
9385
  "/api/across": {
@@ -8775,8 +9519,11 @@ var OPS = {
8775
9519
  "/api/setup": {
8776
9520
  get: {
8777
9521
  id: "getSetup",
8778
- summary: "The setup checklist until the catalog is accepted, with a plain fix for each step",
9522
+ summary: "The setup checklist until the catalog is accepted, with a plain fix for each step; the machine step says `checking` while the machine's checks run",
8779
9523
  tag: "system",
9524
+ params: [
9525
+ q("machine", { type: "string", enum: ["wait"] }, "Wait for the machine's checks instead of answering with the machine step checking")
9526
+ ],
8780
9527
  ok: {
8781
9528
  status: 200,
8782
9529
  schema: { type: "object", required: ["steps", "baselined"] },
@@ -8969,7 +9716,7 @@ var OPS = {
8969
9716
  "/api/ask": {
8970
9717
  get: {
8971
9718
  id: "ask",
8972
- summary: "Answer a plain-language question from the catalog; the query used is always returned",
9719
+ summary: "Answer a plain-language question from the catalog; the query used is always returned. 3.6.0 (ADR 0191): `knowledge` (KnowledgeAnswerView) says what the organisation's knowledge items, wiki snapshots and inputs/ files say to it, each cited",
8973
9720
  tag: "catalog",
8974
9721
  params: [q("q", str3, "The question, e.g. who calls ledger-api?")],
8975
9722
  ok: {
@@ -9422,10 +10169,11 @@ var OPS = {
9422
10169
  "/api/workspace/sync": {
9423
10170
  post: {
9424
10171
  id: "syncWorkspace",
9425
- summary: "Clone or update base clones",
10172
+ summary: "Clone or update base clones. 3.0.0 (review round 48): 409 while a sync runs on this server",
9426
10173
  tag: "workspace",
9427
10174
  body: ScanRequest.pick({ repos: true }),
9428
- ok: { status: 202, schema: "JobAccepted", description: "Job started" }
10175
+ ok: { status: 202, schema: "JobAccepted", description: "Job started" },
10176
+ errors: [409]
9429
10177
  }
9430
10178
  },
9431
10179
  "/api/scan": {
@@ -9441,11 +10189,11 @@ var OPS = {
9441
10189
  "/api/reconcile": {
9442
10190
  post: {
9443
10191
  id: "startReconcile",
9444
- summary: "Check a diagram against the catalog",
10192
+ summary: "Check a diagram against the catalog. 3.0.0 (review round 48): 409 while a reconcile runs on this server",
9445
10193
  tag: "scans",
9446
10194
  body: ReconcileRequest,
9447
10195
  ok: { status: 202, schema: "JobAccepted", description: "Job started" },
9448
- errors: [404]
10196
+ errors: [404, 409]
9449
10197
  }
9450
10198
  },
9451
10199
  "/api/jobs/{jobId}": {
@@ -9513,7 +10261,7 @@ var OPS = {
9513
10261
  },
9514
10262
  post: {
9515
10263
  id: "proposeForReview",
9516
- summary: "2.65.0 (ADR 0183): on the person's yes, commit exactly those files to the branch, push it and open the PR; a person merges",
10264
+ summary: "2.65.0 (ADR 0183): on the person's yes, commit exactly those files to the branch, push it and open the PR; a person merges. 3.0.0 (ADR 0186): needs the person's confirmation (`propose`, the scope), else 403",
9517
10265
  tag: "workspace",
9518
10266
  body: ProposeRequest,
9519
10267
  ok: {
@@ -9522,7 +10270,7 @@ var OPS = {
9522
10270
  description: "Started: its job's result is the code and the lines"
9523
10271
  },
9524
10272
  // 2.68.0: 409 while another local step (Apply, Propose, Bring in) runs.
9525
- errors: [400, 409]
10273
+ errors: [400, 403, 409]
9526
10274
  }
9527
10275
  },
9528
10276
  "/api/owner-questions": {
@@ -9533,6 +10281,17 @@ var OPS = {
9533
10281
  ok: { status: 200, schema: "OwnerQuestionList", description: "OK" }
9534
10282
  }
9535
10283
  },
10284
+ "/api/owner-questions/{id}/send": {
10285
+ post: {
10286
+ id: "sendOwnerQuestion",
10287
+ 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",
10288
+ tag: "questions",
10289
+ params: [p("id")],
10290
+ body: SendOwnerAskRequest,
10291
+ ok: { status: 200, schema: "SentOwnerAsk", description: "Sent, or why not" },
10292
+ errors: [400, 403, 404]
10293
+ }
10294
+ },
9536
10295
  "/api/owner-questions/{id}/answer": {
9537
10296
  post: {
9538
10297
  id: "answerOwnerQuestion",
@@ -9576,10 +10335,69 @@ var OPS = {
9576
10335
  errors: [404]
9577
10336
  }
9578
10337
  },
9579
- "/api/changes/{changeId}/owners": {
9580
- put: {
9581
- id: "setChangeOwners",
9582
- summary: "2.83.0 (ninth UX walk): name the change's owners per role (product owner, architect, business analyst, tech lead) in change.yaml, on the person's click",
10338
+ "/api/changes/{changeId}/owners/suggested": {
10339
+ get: {
10340
+ id: "suggestChangeOwners",
10341
+ summary: "3.6.0 (ADR 0191): who roles.yaml suggests for each role the change doesn't name yet: the team owning its repos, else the organisation's default; a person accepts one with PUT .../owners",
10342
+ tag: "changes",
10343
+ params: [p("changeId")],
10344
+ ok: { status: 200, schema: "OwnerSuggestionList", description: "OK" },
10345
+ errors: [400, 404]
10346
+ }
10347
+ },
10348
+ "/api/changes/{changeId}/work-items": {
10349
+ get: {
10350
+ id: "planWorkItems",
10351
+ summary: "3.6.0 (ADR 0191): the feature, stories and tasks the plan puts in the work tracker, and what sync.yaml remembers of each (atticus ado sync --dry-run)",
10352
+ tag: "changes",
10353
+ params: [p("changeId")],
10354
+ ok: { status: 200, schema: "WorkItemPlan", description: "OK" },
10355
+ errors: [400, 404, 422]
10356
+ },
10357
+ post: {
10358
+ id: "syncWorkItems",
10359
+ summary: "3.6.0 (ADR 0191): put them in the work tracker as the signed-in person: with a manual tracker a step each (the fields to copy, the id to record); with a live one, on the person's `work-items` confirmation. sync.yaml keeps each id, so a later sync updates rather than duplicates. 3.9.0: with `job: true`, 202 JobAccepted at once; the job's result `answer` is the result, or `problem` when refused",
10360
+ tag: "changes",
10361
+ params: [p("changeId")],
10362
+ body: WorkItemSyncRequest,
10363
+ ok: { status: 200, schema: "WorkItemSyncResult", description: "Synced" },
10364
+ alsoOk: { status: 202, schema: "JobAccepted", description: "Started as a job (`job: true`)" },
10365
+ errors: [400, 403, 404, 422]
10366
+ }
10367
+ },
10368
+ "/api/changes/{changeId}/stories/shape": {
10369
+ get: {
10370
+ id: "getStoryShape",
10371
+ summary: "3.6.0 (ADR 0191): the business analyst's renames, splits, merges and added stories, each task's story as the last draft mapped it, and what is uncovered",
10372
+ tag: "changes",
10373
+ params: [p("changeId")],
10374
+ ok: { status: 200, schema: "StoryShapeView", description: "OK" },
10375
+ errors: [400, 404]
10376
+ },
10377
+ post: {
10378
+ id: "shapeStories",
10379
+ summary: "3.6.0 (ADR 0191): rename, split, merge or add a story in plain words, as the signed-in person; a rename and a merge keep the number, a split's new part and an added story take the next free one. The next draft of the stories maps the tasks to them",
10380
+ tag: "changes",
10381
+ params: [p("changeId")],
10382
+ body: StoryShapeRequest,
10383
+ ok: { status: 201, schema: "StoryShapeView", description: "Recorded" },
10384
+ errors: [400, 404, 422]
10385
+ }
10386
+ },
10387
+ "/api/changes/{changeId}/stories/shape/{entryId}/remove": {
10388
+ post: {
10389
+ id: "removeStoryShape",
10390
+ summary: "3.6.0 (ADR 0191): take back a shaping no draft has read yet; one a draft applied stays, and a later one changes it",
10391
+ tag: "changes",
10392
+ params: [p("changeId"), p("entryId")],
10393
+ ok: { status: 200, schema: "StoryShapeView", description: "Removed" },
10394
+ errors: [400, 404, 422]
10395
+ }
10396
+ },
10397
+ "/api/changes/{changeId}/owners": {
10398
+ put: {
10399
+ id: "setChangeOwners",
10400
+ summary: "2.83.0 (ninth UX walk): name the change's owners per role (product owner, architect, business analyst, tech lead) in change.yaml, on the person's click",
9583
10401
  tag: "changes",
9584
10402
  params: [p("changeId")],
9585
10403
  body: ChangeOwnersRequest,
@@ -9604,7 +10422,7 @@ var OPS = {
9604
10422
  "/api/changes/{changeId}/release-prs": {
9605
10423
  post: {
9606
10424
  id: "raiseReleasePrs",
9607
- summary: "Raise one release PR per code repo from change/<id> into its default branch, as the signed-in person (ADR 0184)",
10425
+ summary: "Raise one release PR per code repo from change/<id> into its default branch, as the signed-in person (ADR 0184). 3.0.0 (ADR 0186): needs the person's confirmation (`release-prs`, the change), else 403",
9608
10426
  tag: "changes",
9609
10427
  params: [p("changeId")],
9610
10428
  body: ReleasePrsRequest,
@@ -9613,18 +10431,18 @@ var OPS = {
9613
10431
  schema: "LinesView",
9614
10432
  description: "Raised: what each repo's release PR said"
9615
10433
  },
9616
- errors: [400, 404, 422]
10434
+ errors: [400, 403, 404, 422]
9617
10435
  }
9618
10436
  },
9619
10437
  "/api/changes/{changeId}/sync": {
9620
10438
  post: {
9621
10439
  id: "syncChange",
9622
- summary: "Refresh the change from its hand-off PR and advance it when merged (ADR 0043)",
10440
+ summary: "Refresh the change from its hand-off PR and advance it when merged (ADR 0043). 3.0.0 (ADR 0186): merges a ready PR only with the person's confirmation (`merge`, the change); without one it only reads, and a confirmation that isn't valid is 403",
9623
10441
  tag: "changes",
9624
10442
  params: [p("changeId")],
9625
10443
  body: SyncRequest,
9626
10444
  ok: { status: 200, schema: "ChangeDetail", description: "OK" },
9627
- errors: [400, 404, 422]
10445
+ errors: [400, 403, 404, 422]
9628
10446
  }
9629
10447
  },
9630
10448
  "/api/changes/{changeId}/artifacts/{artifact}": {
@@ -9667,9 +10485,10 @@ var OPS = {
9667
10485
  "/api/changes/{changeId}/tasks/{taskId}/pr": {
9668
10486
  post: {
9669
10487
  id: "raiseTaskPr",
9670
- summary: "2.69.0 (sixth UX walk): on the person's yes, push a drafted task's branch and open its PR into the change branch",
10488
+ summary: "2.69.0 (sixth UX walk): on the person's yes, push a drafted task's branch and open its PR into the change branch. 3.0.0 (ADR 0186): needs the person's confirmation (`task-pr`, `<change>/<task>`), else 403",
9671
10489
  tag: "changes",
9672
10490
  params: [p("changeId"), p("taskId")],
10491
+ body: ConfirmedRequest,
9673
10492
  ok: { status: 201, schema: "Task", description: "The task, its PR raised" },
9674
10493
  errors: [403, 404, 409, 422]
9675
10494
  }
@@ -9687,7 +10506,7 @@ var OPS = {
9687
10506
  "/api/changes/{changeId}/tasks/run-ready": {
9688
10507
  post: {
9689
10508
  id: "runReadyTasks",
9690
- summary: "2.79.0 (ADR 0181 part 4): Run all ready tasks, one task run each in order as one job, stopping on the first that needs a person; the click is the approval for draft, never the pr level",
10509
+ summary: "2.79.0 (ADR 0181 part 4): Run all ready tasks, one task run each in order as one job, stopping on the first that needs a person; the click is the approval for draft, never the pr level. 3.1.0: in model mode 403 unless runtime.yaml sends the key where the person last confirmed",
9691
10510
  tag: "changes",
9692
10511
  params: [p("changeId")],
9693
10512
  body: RunReadyRequest,
@@ -9703,24 +10522,56 @@ var OPS = {
9703
10522
  params: [p("changeId"), p("taskId")],
9704
10523
  body: TaskDoneRequest,
9705
10524
  ok: { status: 200, schema: "Task", description: "The task as tasks.md now says it" },
9706
- errors: [400, 403, 404]
10525
+ errors: [400, 403, 404, 409]
10526
+ }
10527
+ },
10528
+ "/api/propose/upstream": {
10529
+ post: {
10530
+ id: "setUpstream",
10531
+ summary: "3.3.0 (app-only audit): set the upstream of the branch checked out to the same branch on a remote, a local setting (nothing is sent), as a local job; refused (the job's result says why) for any other branch",
10532
+ tag: "workspace",
10533
+ body: UpstreamRequest,
10534
+ ok: { status: 202, schema: "JobAccepted", description: "Job started" },
10535
+ errors: [400, 409]
10536
+ }
10537
+ },
10538
+ "/api/changes/{changeId}/handoff/push": {
10539
+ post: {
10540
+ id: "pushHandoff",
10541
+ summary: "3.3.0 (app-only audit): Push again: push the open hand-off's branch, kept here when its push failed, by name and never forced; needs the person's confirmation (`handoff`, the change), else 403; 422 with git's words when the push fails",
10542
+ tag: "changes",
10543
+ params: [p("changeId")],
10544
+ body: ConfirmedRequest,
10545
+ ok: { status: 200, schema: "ChangeDetail", description: "The change, its branch pushed" },
10546
+ errors: [403, 404, 422]
10547
+ }
10548
+ },
10549
+ "/api/changes/{changeId}/tasks/{taskId}/build": {
10550
+ post: {
10551
+ id: "buildTask",
10552
+ summary: "3.3.0 (app-only audit): Build and raise PR on a task drafted but not built (UNVERIFIED) or taken over by a person: build it with its repo's build command as it is now, and with `raise` push its branch and open its PR (needs the person's confirmation, `task-pr`, `<change>/<task>`, else 403)",
10553
+ tag: "changes",
10554
+ params: [p("changeId"), p("taskId")],
10555
+ body: TaskBuildRequest,
10556
+ ok: { status: 200, schema: "Task", description: "The task, built (201 with its PR raised)" },
10557
+ errors: [400, 403, 404, 409, 422]
9707
10558
  }
9708
10559
  },
9709
10560
  "/api/changes/{changeId}/workspace": {
9710
10561
  post: {
9711
10562
  id: "openWorkspace",
9712
- summary: "Create the change's worktrees and editor workspaces",
10563
+ summary: "Create the change's worktrees and editor workspaces; 3.1.0: 409 while a sync of one of its repos' base clones runs elsewhere",
9713
10564
  tag: "changes",
9714
10565
  params: [p("changeId")],
9715
10566
  body: OpenWorkspaceRequest,
9716
10567
  ok: { status: 200, schema: "ChangeRepos", description: "OK" },
9717
- errors: [400, 404]
10568
+ errors: [400, 404, 409]
9718
10569
  }
9719
10570
  },
9720
10571
  "/api/changes/{changeId}/handoff": {
9721
10572
  post: {
9722
10573
  id: "handOff",
9723
- summary: "Open the phase's hand-off PR after its gate passes",
10574
+ summary: "Open the phase's hand-off PR after its gate passes. 3.0.0 (ADR 0186): needs the person's confirmation (`handoff`, the change), else 403",
9724
10575
  tag: "changes",
9725
10576
  params: [p("changeId")],
9726
10577
  body: HandoffRequest,
@@ -9739,12 +10590,12 @@ var OPS = {
9739
10590
  },
9740
10591
  post: {
9741
10592
  id: "startRun",
9742
- summary: "Prepare an AI run (hand-off by default)",
10593
+ summary: "Prepare an AI run (hand-off by default); 3.1.0: in model mode 403 unless runtime.yaml sends the key where the person last confirmed (ADR 0186 addendum), and 409 while a sync of the task's repo runs elsewhere",
9743
10594
  tag: "ai",
9744
10595
  params: [p("changeId")],
9745
10596
  body: StartRunRequest,
9746
10597
  ok: { status: 201, schema: "RunView", description: "Prepared" },
9747
- errors: [400, 403, 404, 422]
10598
+ errors: [400, 403, 404, 409, 422]
9748
10599
  }
9749
10600
  },
9750
10601
  "/api/changes/{changeId}/critic": {
@@ -9782,7 +10633,7 @@ var OPS = {
9782
10633
  },
9783
10634
  post: {
9784
10635
  id: "startStep",
9785
- summary: "Start an AI step on the server with runtime.yaml's model, as a job (ADR 0106); 409 when no model is configured, or (2.68.0) while another AI step runs",
10636
+ summary: "Start an AI step on the server with runtime.yaml's model, as a job (ADR 0106); 409 when no model is configured, or (2.68.0) while another AI step runs; 3.1.0: 403 unless runtime.yaml sends the key where the person last confirmed (ADR 0186 addendum)",
9786
10637
  tag: "ai",
9787
10638
  body: StartStepRequest,
9788
10639
  ok: {
@@ -9790,7 +10641,7 @@ var OPS = {
9790
10641
  schema: { type: "object", required: ["jobId", "model"] },
9791
10642
  description: "Started"
9792
10643
  },
9793
- errors: [400, 409]
10644
+ errors: [400, 403, 409]
9794
10645
  }
9795
10646
  },
9796
10647
  "/api/runs/handoff": {
@@ -9870,6 +10721,67 @@ var OPS = {
9870
10721
  errors: [409]
9871
10722
  }
9872
10723
  },
10724
+ "/api/facts/apply-all": {
10725
+ post: {
10726
+ id: "applyAllFacts",
10727
+ summary: "3.5.0 (ADR 0188): run atticus verify --all --write as a local job, as Apply after a declaration or an owner set on the canvas",
10728
+ tag: "workspace",
10729
+ ok: {
10730
+ status: 202,
10731
+ schema: "JobAccepted",
10732
+ description: "Started: its job's result is the code and the lines verify printed"
10733
+ },
10734
+ errors: [409]
10735
+ }
10736
+ },
10737
+ "/api/estate/join": {
10738
+ post: {
10739
+ id: "joinEstate",
10740
+ summary: "3.5.0 (ADR 0188): run atticus estate join as a local job: each flow's calls to other repos followed into the flows they reach",
10741
+ tag: "workspace",
10742
+ ok: { status: 202, schema: "JobAccepted", description: "Job started" },
10743
+ errors: [409]
10744
+ }
10745
+ },
10746
+ "/api/knowledge/sources/sync": {
10747
+ post: {
10748
+ id: "syncAllKnowledgeSources",
10749
+ summary: "3.5.0 (ADR 0188): run atticus sources sync as a local job: every wiki in sources.yaml read into a dated snapshot",
10750
+ tag: "knowledge",
10751
+ ok: { status: 202, schema: "JobAccepted", description: "Job started" },
10752
+ errors: [409]
10753
+ }
10754
+ },
10755
+ "/api/workspace/prune": {
10756
+ post: {
10757
+ id: "pruneWorktrees",
10758
+ summary: "3.5.0 (ADR 0188): run atticus workspace prune as a local job, for one change or every change with worktrees; a worktree with uncommitted work is kept",
10759
+ tag: "workspace",
10760
+ body: PruneRequest,
10761
+ ok: { status: 202, schema: "JobAccepted", description: "Job started" },
10762
+ errors: [400, 409]
10763
+ }
10764
+ },
10765
+ "/api/changes/{changeId}/tasks/{taskId}/context": {
10766
+ get: {
10767
+ id: "getTaskContext",
10768
+ summary: "3.5.0 (ADR 0188): a task's context as atticus task context --markdown prints it, for the person to copy into their assistant",
10769
+ tag: "changes",
10770
+ params: [p("changeId"), p("taskId")],
10771
+ ok: { status: 200, schema: "TaskContextView", description: "OK" },
10772
+ errors: [400]
10773
+ }
10774
+ },
10775
+ "/api/history/recording": {
10776
+ put: {
10777
+ id: "setPromptHistoryRecording",
10778
+ summary: "3.5.0 (ADR 0188): atticus history on|off, this machine's recording (.atticus/me.yaml); the org pack's history.record: false still holds",
10779
+ tag: "ai",
10780
+ body: HistoryRecordingRequest,
10781
+ ok: { status: 200, schema: "HistoryRecordingView", description: "OK" },
10782
+ errors: [400]
10783
+ }
10784
+ },
9873
10785
  "/api/upgrade": {
9874
10786
  get: {
9875
10787
  id: "getUpgrade",
@@ -9885,6 +10797,131 @@ var OPS = {
9885
10797
  errors: [409]
9886
10798
  }
9887
10799
  },
10800
+ // ADR 0190: settings and setup in the app, "Edit, then Propose".
10801
+ "/api/setup/metarepo": {
10802
+ get: {
10803
+ id: "getSetupMetarepo",
10804
+ summary: "3.5.0 (ADR 0190): whether the folder the app runs in is a metarepo, and what Create the metarepo here would use (a name and platform from the folder's name, the metarepo's id on the Git host from its origin)",
10805
+ tag: "run",
10806
+ ok: { status: 200, schema: "SetupMetarepoView", description: "OK" }
10807
+ },
10808
+ post: {
10809
+ id: "createMetarepo",
10810
+ summary: "Create the metarepo in this folder with atticus init's own code (name, platform, owner; the Git host manual, with the metarepo's id when given or read from origin), brought up to date as init does. Local files only: nothing is pushed. 409 when it is a metarepo already",
10811
+ tag: "run",
10812
+ body: CreateMetarepoRequest,
10813
+ ok: { status: 201, schema: "LinesView", description: "Created" },
10814
+ errors: [400, 409, 422]
10815
+ }
10816
+ },
10817
+ "/api/setup/open": {
10818
+ post: {
10819
+ id: "openFolder",
10820
+ summary: "Open another folder: start the app for that folder (a full path on this machine) on a free port, for the same person, and give its address; a folder that isn't a metarepo offers Create there",
10821
+ tag: "run",
10822
+ body: OpenFolderRequest,
10823
+ ok: { status: 200, schema: "OpenFolderView", description: "OK" },
10824
+ errors: [400, 404]
10825
+ }
10826
+ },
10827
+ "/api/setup/repos/plan": {
10828
+ post: {
10829
+ id: "planRepos",
10830
+ summary: "The repos pasted clone URLs (one a line, up to 500) or a folder of clones (repos discover's own code, a dry run) would add: each normalised URL and the id repo add gives it, a clone URL a manifest lists already left out, a taken id given -2, and a folder's type from its files. A folder with several platforms and none given reads nothing and answers the platforms to choose from (`platforms`, no `platform`). Writes nothing",
10831
+ tag: "run",
10832
+ body: ReposPlanRequest,
10833
+ ok: { status: 200, schema: "ReposPlanView", description: "OK" },
10834
+ errors: [400, 404, 409, 422]
10835
+ }
10836
+ },
10837
+ "/api/setup/repos": {
10838
+ post: {
10839
+ id: "addRepos",
10840
+ summary: "Add the repos the person ticked to the platform's repos.manifest.yaml (core's addManifestRepos: comments, order and line endings kept, the manifest checked first); a description is the person's own (verified). With preview: the lines it would change, nothing written. Propose for review then opens the PR",
10841
+ tag: "run",
10842
+ body: AddReposRequest,
10843
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10844
+ errors: [400, 404, 409, 422]
10845
+ }
10846
+ },
10847
+ "/api/repos/{repoId}/type/detect": {
10848
+ post: {
10849
+ id: "detectRepoType",
10850
+ summary: "Detect a cloned repo's type: the org pack's repo types (atticus repo-type detect) when it has any, else the type repo add reads from the files. Writes nothing; 409 when the repo isn't cloned here",
10851
+ tag: "run",
10852
+ params: [p("repoId")],
10853
+ ok: { status: 200, schema: "RepoTypeDetectView", description: "OK" },
10854
+ errors: [404, 409, 422]
10855
+ }
10856
+ },
10857
+ "/api/repos/{repoId}/type": {
10858
+ put: {
10859
+ id: "setRepoType",
10860
+ summary: "Set a repo's type in the manifest that lists it (comments and order kept); with preview, the line it would change",
10861
+ tag: "run",
10862
+ params: [p("repoId")],
10863
+ body: RepoTypeRequest,
10864
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10865
+ errors: [400, 404, 422]
10866
+ }
10867
+ },
10868
+ "/api/setup/adapters": {
10869
+ get: {
10870
+ id: "getAdapters",
10871
+ summary: "The outside systems runtime.yaml names (Git host, work tracker, service desk, notifications, wiki, design tool): the types its schema takes for each, the settings Atticus reads, what is set now, and runtime.yaml's sha256 to send back with a write. No secret is ever in them",
10872
+ tag: "run",
10873
+ ok: { status: 200, schema: "AdaptersView", description: "OK" }
10874
+ }
10875
+ },
10876
+ "/api/setup/adapters/{kind}": {
10877
+ put: {
10878
+ id: "setAdapter",
10879
+ summary: "Set (or with null, take out) one outside system in runtime.yaml, checked with the Runtime schema first (a type it doesn't take, a setting named like a secret or a value that looks like a token is refused, 422); edited in place, so comments, value types and line endings are kept. With `baseSha256` (GET's `sha256`), a runtime.yaml changed since is 409. With preview, the lines it would change. A token is kept in the credential store from the terminal (atticus secret set), never through this API",
10880
+ tag: "run",
10881
+ params: [p("kind")],
10882
+ body: AdapterRequest,
10883
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10884
+ errors: [400, 404, 409, 422]
10885
+ }
10886
+ },
10887
+ "/api/setup/file": {
10888
+ get: {
10889
+ id: "getOrgPackFile",
10890
+ summary: "One org-pack file for the raw editor (a path inside org-pack/ ending .yaml, .md, .txt or .json): its text, its sha256 and whether it is checked with a schema",
10891
+ tag: "run",
10892
+ params: [q("path")],
10893
+ ok: { status: 200, schema: "OrgPackFileView", description: "OK" },
10894
+ errors: [404, 422]
10895
+ },
10896
+ put: {
10897
+ id: "putOrgPackFile",
10898
+ summary: "The raw editor's write, the fallback for a setting with no form: the file's whole text, checked with its schema (YAML that doesn't parse, or doesn't read, is 422), onto the file as opened (another edit meanwhile is 409). With preview, the lines it would change. A runtime.yaml edit that moves where the model's key goes needs the person's confirmation (`ai-model`, `model`), else 403; a value that looks like a key is refused",
10899
+ tag: "run",
10900
+ body: OrgPackFileRequest,
10901
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10902
+ errors: [400, 403, 409, 422]
10903
+ }
10904
+ },
10905
+ "/api/setup/patterns": {
10906
+ post: {
10907
+ id: "addPattern",
10908
+ summary: "A new integration pattern from the app's form, as its own org-pack/patterns/<code>.yaml, checked with the pattern schema; a code that is there already is 409 (edit it in the raw editor). With preview, the lines it would write",
10909
+ tag: "run",
10910
+ body: PatternRequest,
10911
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10912
+ errors: [400, 409, 422]
10913
+ }
10914
+ },
10915
+ "/api/setup/sources": {
10916
+ post: {
10917
+ id: "addSource",
10918
+ summary: "A wiki added to sources.yaml with atticus sources add's own code (its checks, its id, the path written relative to the org pack); comments and line endings kept. A location with a user name or password in it is refused (422: Git's credential helper or an environment variable gives them), and so is a sources.yaml changed meanwhile (409). With preview, the entry it would add",
10919
+ tag: "run",
10920
+ body: SourceRequest,
10921
+ ok: { status: 200, schema: "FileEditView", description: "OK" },
10922
+ errors: [400, 409, 422]
10923
+ }
10924
+ },
9888
10925
  "/api/decisions": {
9889
10926
  get: {
9890
10927
  id: "getDecisions",
@@ -10070,6 +11107,24 @@ var OPS = {
10070
11107
  errors: [404]
10071
11108
  }
10072
11109
  },
11110
+ "/api/activity": {
11111
+ get: {
11112
+ id: "listActivity",
11113
+ summary: "Everything Atticus is doing or did lately on this metarepo, newest first: the app's jobs, a Copilot run, the commands run in a terminal, an editor or a Copilot session, and the hand-off runs that wait for an assistant (ADR 0187)",
11114
+ tag: "ai",
11115
+ ok: { status: 200, schema: "ActivityList", description: "OK" }
11116
+ }
11117
+ },
11118
+ "/api/activity/{id}/lines": {
11119
+ get: {
11120
+ id: "getActivityLines",
11121
+ summary: "One activity's printed lines from a line on (from), or its last ones; a Copilot run's are its tabs (ADR 0187)",
11122
+ tag: "ai",
11123
+ params: [p("id"), q("from", str3, "The number of the first line wanted")],
11124
+ ok: { status: 200, schema: "ActivityLines", description: "OK" },
11125
+ errors: [400, 404]
11126
+ }
11127
+ },
10073
11128
  "/api/copilot-runs/{runId}/stop": {
10074
11129
  post: {
10075
11130
  id: "stopCopilotRun",
@@ -10118,10 +11173,13 @@ var OPS = {
10118
11173
  "/api/runs/{runId}/done": {
10119
11174
  post: {
10120
11175
  id: "markRunDone",
10121
- summary: "Mark done: validate the hand-off output now. 2.67.0 (fourth UX walk): a step the app prepared then resumes, writing what the answer said; `lines` says what happened and `next` names the step's next run when it offers another prompt",
11176
+ summary: "Mark done: validate the hand-off output now. 2.67.0 (fourth UX walk): a step the app prepared then resumes, writing what the answer said; `lines` says what happened and `next` names the step's next run when it offers another prompt. 3.5.0 (ADR 0188): a read of a repo's last batch is put on the map (verify --write), named in `applied`. 3.9.0: with `job: true`, 202 JobAccepted at once; the job's result `answer` is this view, or `problem` when refused",
10122
11177
  tag: "ai",
10123
11178
  params: [p("runId")],
11179
+ body: RunDoneRequest,
11180
+ bodyOptional: true,
10124
11181
  ok: { status: 200, schema: "RunDoneView", description: "OK" },
11182
+ alsoOk: { status: 202, schema: "JobAccepted", description: "Started as a job (`job: true`)" },
10125
11183
  errors: [404, 409, 422]
10126
11184
  }
10127
11185
  },
@@ -10155,9 +11213,10 @@ var OPS = {
10155
11213
  q("gate"),
10156
11214
  q("state"),
10157
11215
  q("lens", { type: "string", enum: Lens.options }),
10158
- q("severity", { type: "string", enum: Severity.options })
11216
+ q("severity", { type: "string", enum: Severity.options }),
11217
+ q("asks", { type: "string", enum: ["business", "design", "delivery"] }, "3.6.0 (ADR 0191): only findings that ask at this level")
10159
11218
  ],
10160
- ok: { status: 200, schema: arrayOf("Finding"), description: "OK" }
11219
+ ok: { status: 200, schema: arrayOf("FindingView"), description: "OK" }
10161
11220
  }
10162
11221
  },
10163
11222
  "/api/findings/{changeId}/{findingId}": {
@@ -10223,12 +11282,12 @@ var OPS = {
10223
11282
  },
10224
11283
  post: {
10225
11284
  id: "runStep",
10226
- summary: "Run a step with a team's own tool; the shown inputs' sha-256 is the approval",
11285
+ summary: "Run a step with a team's own tool on the shown inputs (their sha-256). 3.0.0 (ADR 0186): needs the person's confirmation (`step-run`, the step), else 403",
10227
11286
  tag: "release",
10228
11287
  params: [p("stepId")],
10229
11288
  body: StepRunRequest,
10230
11289
  ok: { status: 200, schema: { type: "object" }, description: "OK" },
10231
- errors: [400, 404, 422]
11290
+ errors: [400, 403, 404, 422]
10232
11291
  }
10233
11292
  },
10234
11293
  "/api/release": {
@@ -10391,11 +11450,11 @@ var OPS = {
10391
11450
  },
10392
11451
  put: {
10393
11452
  id: "putAiSettings",
10394
- summary: "Write the AI settings to runtime.yaml: checked against the Runtime schema, keeping what it doesn't change; refuses anything that looks like a key. 2.84.0: takes decide (ADR 0181: links, questions, minPrecision), lifting a version 3 file to 4",
11453
+ summary: "Write the AI settings to runtime.yaml: checked against the Runtime schema, keeping what it doesn't change; refuses anything that looks like a key. 2.84.0: takes decide (ADR 0181: links, questions, minPrecision), lifting a version 3 file to 4. 3.0.0 (ADR 0186): keyEnv is a variable starting ATTICUS_, one of the model providers' own key names (the list is in the model-providers package) or a name kept in this machine's credential store (422 otherwise); a change of the provider, keyEnv or an address needs the person's confirmation (`ai-model`, `model`) as `confirmation`, else 403",
10395
11454
  tag: "run",
10396
11455
  body: z30.record(z30.string(), z30.unknown()),
10397
11456
  ok: { status: 200, schema: { type: "object" }, description: "OK" },
10398
- errors: [409, 422]
11457
+ errors: [403, 409, 422]
10399
11458
  }
10400
11459
  },
10401
11460
  "/api/component-types": {
@@ -10419,10 +11478,11 @@ var OPS = {
10419
11478
  "/api/settings/ai/test": {
10420
11479
  post: {
10421
11480
  id: "testAiProvider",
10422
- summary: "Ask the configured model provider one short question with nothing of the estate in it, and say whether it answered",
11481
+ summary: "Ask the configured model provider one short question with nothing of the estate in it, and say whether it answered. 3.0.0 (ADR 0186): when runtime.yaml's model settings differ from the committed ones (HEAD), it needs the person's confirmation (`ai-test`, `model`), else 403. 3.1.0: also whenever they send the key to an address the person hasn't confirmed, committed or not; a confirmed Test makes it the confirmed address",
10423
11482
  tag: "run",
11483
+ body: ConfirmedRequest,
10424
11484
  ok: { status: 200, schema: { type: "object" }, description: "OK" },
10425
- errors: [409]
11485
+ errors: [403, 409]
10426
11486
  }
10427
11487
  },
10428
11488
  "/api/settings/executors/check": {
@@ -10554,6 +11614,17 @@ var OPS = {
10554
11614
  errors: [404, 422]
10555
11615
  }
10556
11616
  },
11617
+ "/api/questions/{id}/route": {
11618
+ post: {
11619
+ id: "routeQuestion",
11620
+ summary: "3.6.0 (ADR 0191): move a question to another role (product, architecture, analysis, delivery), as the signed-in person; the question keeps its answer, and `routed` says from which role, by whom and when",
11621
+ tag: "questions",
11622
+ params: [p("id")],
11623
+ body: RouteQuestionRequest,
11624
+ ok: { status: 200, schema: { type: "object" }, description: "The question, routed" },
11625
+ errors: [400, 404, 422]
11626
+ }
11627
+ },
10557
11628
  "/api/questions/{id}/answer": {
10558
11629
  post: {
10559
11630
  id: "answerQuestion",
@@ -10648,6 +11719,16 @@ var OPS = {
10648
11719
  errors: [400, 404, 422]
10649
11720
  }
10650
11721
  },
11722
+ "/api/knowledge/passage": {
11723
+ get: {
11724
+ id: "knowledgePassage",
11725
+ summary: "3.6.0 (ADR 0191): one section of a wiki snapshot page or an inputs/ file, by its id (<source>/<page>#<heading>), to open it in place",
11726
+ tag: "knowledge",
11727
+ params: [q("id", str3, "The section's id, as a change's knowledge lists it")],
11728
+ ok: { status: 200, schema: "KnowledgePassageView", description: "OK" },
11729
+ errors: [400, 404]
11730
+ }
11731
+ },
10651
11732
  "/api/knowledge/search": {
10652
11733
  get: {
10653
11734
  id: "searchWikis",
@@ -10787,6 +11868,25 @@ var OPS = {
10787
11868
  errors: [400, 404, 409, 422]
10788
11869
  }
10789
11870
  },
11871
+ "/api/changes/{changeId}/stages/{stage}/thread": {
11872
+ get: {
11873
+ id: "getStageThread",
11874
+ summary: "3.5.0 (ADR 0189): a stage of the change as one conversation: the prompts, the assistant's answers and their checks, the critic's findings, the questions, the replies and corrections, and the questions that couldn't be kept, in order",
11875
+ tag: "changes",
11876
+ params: [p("changeId"), p("stage", { schema: { type: "string", enum: [...THREAD_STAGES] } })],
11877
+ ok: { status: 200, schema: "StageThreadView", description: "OK" },
11878
+ errors: [400, 404]
11879
+ },
11880
+ post: {
11881
+ id: "postToStageThread",
11882
+ summary: "3.5.0 (ADR 0189): a person's reply to the stage's assistant (read by its next round as their answer), a comment on a finding, or keeping a dropped question anyway",
11883
+ tag: "changes",
11884
+ params: [p("changeId"), p("stage", { schema: { type: "string", enum: [...THREAD_STAGES] } })],
11885
+ body: StageThreadPost,
11886
+ ok: { status: 200, schema: "StageThreadPostResult", description: "Written" },
11887
+ errors: [400, 404, 409, 422]
11888
+ }
11889
+ },
10790
11890
  "/api/changes/{changeId}/knowledge": {
10791
11891
  get: {
10792
11892
  id: "getChangeKnowledge",
@@ -10891,9 +11991,266 @@ import { isMap as isMap8, parseDocument as parseDocument8 } from "yaml";
10891
11991
  // packages/core/dist/runtime-migrate.js
10892
11992
  import { isMap as isMap9, parseDocument as parseDocument9 } from "yaml";
10893
11993
 
11994
+ // packages/core/dist/glob.js
11995
+ var notSlash = (c) => c !== "/";
11996
+ var anyChar = (c) => !/[\n\r\u2028\u2029]/.test(c);
11997
+ var Builder = class {
11998
+ states = [];
11999
+ add(s) {
12000
+ this.states.push(s);
12001
+ return this.states.length - 1;
12002
+ }
12003
+ /** `c*` looping on a test, then on to next. */
12004
+ loop(test, next) {
12005
+ const split = this.add({ kind: "split", outs: [] });
12006
+ const ch = this.add({ kind: "char", test, out: split });
12007
+ this.states[split].outs.push(ch, next);
12008
+ return split;
12009
+ }
12010
+ /** `(?:.*\/)?` then next: any folders, or none. */
12011
+ folders(next) {
12012
+ const slash = this.add({ kind: "char", test: (c) => c === "/", out: next });
12013
+ return this.add({ kind: "split", outs: [this.loop(anyChar, slash), next] });
12014
+ }
12015
+ };
12016
+ function tidy(glob) {
12017
+ return glob.trim().replace(/\\/g, "/").replace(/^\.\//, "");
12018
+ }
12019
+ function compile(b, g, next) {
12020
+ const pieces = [];
12021
+ for (let i = 0; i < g.length; i++) {
12022
+ const ch = g[i];
12023
+ if (ch === "*") {
12024
+ if (g[i + 1] === "*") {
12025
+ const slash = g[i + 2] === "/";
12026
+ pieces.push(slash ? (n) => b.folders(n) : (n) => b.loop(anyChar, n));
12027
+ i += slash ? 2 : 1;
12028
+ } else
12029
+ pieces.push((n) => b.loop(notSlash, n));
12030
+ } else if (ch === "?")
12031
+ pieces.push((n) => b.add({ kind: "char", test: notSlash, out: n }));
12032
+ else if (ch === "[") {
12033
+ const end = g.indexOf("]", i + 2);
12034
+ if (end < 0)
12035
+ pieces.push(lit("["));
12036
+ else {
12037
+ const body = g.slice(i + 1, end).replace(/^!/, "^").replace(/\\/g, "\\\\");
12038
+ const re = new RegExp(`^[${body}]$`);
12039
+ pieces.push((n) => b.add({ kind: "char", test: (c) => re.test(c), out: n }));
12040
+ i = end;
12041
+ }
12042
+ } else if (ch === "{") {
12043
+ const end = g.indexOf("}", i);
12044
+ if (end < 0)
12045
+ pieces.push(lit("{"));
12046
+ else {
12047
+ const parts = g.slice(i + 1, end).split(",").map((p2) => {
12048
+ let t = tidy(p2);
12049
+ if (t.startsWith("/"))
12050
+ t = t.slice(1);
12051
+ return t;
12052
+ });
12053
+ const probe = new Builder();
12054
+ for (const p2 of parts)
12055
+ compile(probe, p2, probe.add({ kind: "match" }));
12056
+ pieces.push((n) => b.add({ kind: "split", outs: parts.map((p2) => compile(b, p2, n)) }));
12057
+ i = end;
12058
+ }
12059
+ } else
12060
+ pieces.push(lit(ch));
12061
+ }
12062
+ let at = next;
12063
+ for (let k = pieces.length - 1; k >= 0; k--)
12064
+ at = pieces[k](at);
12065
+ return at;
12066
+ function lit(c) {
12067
+ return (n) => b.add({ kind: "char", test: (x) => x === c, out: n });
12068
+ }
12069
+ }
12070
+ function globMatcher(glob, anyDepth = !glob.replace(/\/$/, "").includes("/")) {
12071
+ let g = tidy(glob);
12072
+ if (g.startsWith("/")) {
12073
+ g = g.slice(1);
12074
+ anyDepth = false;
12075
+ }
12076
+ const b = new Builder();
12077
+ const end = b.add({ kind: "match" });
12078
+ let start = compile(b, g, end);
12079
+ if (anyDepth)
12080
+ start = b.folders(start);
12081
+ const states = b.states;
12082
+ const close = (set, s) => {
12083
+ const stack = [s];
12084
+ while (stack.length) {
12085
+ const at = stack.pop();
12086
+ if (set.has(at))
12087
+ continue;
12088
+ set.add(at);
12089
+ const st = states[at];
12090
+ if (st.kind === "split")
12091
+ for (const o of st.outs)
12092
+ stack.push(o);
12093
+ }
12094
+ };
12095
+ return {
12096
+ test(path) {
12097
+ let live = /* @__PURE__ */ new Set();
12098
+ close(live, start);
12099
+ for (let i = 0; i < path.length; i++) {
12100
+ const c = path[i];
12101
+ const next = /* @__PURE__ */ new Set();
12102
+ for (const s of live) {
12103
+ const st = states[s];
12104
+ if (st.kind === "char" && st.test(c))
12105
+ close(next, st.out);
12106
+ }
12107
+ if (!next.size)
12108
+ return false;
12109
+ live = next;
12110
+ }
12111
+ return live.has(end);
12112
+ }
12113
+ };
12114
+ }
12115
+
12116
+ // packages/core/dist/repo-files.js
12117
+ import { readdir, readFile } from "node:fs/promises";
12118
+ import { join } from "node:path";
12119
+ var LATIN1_HIGH = (
12120
+ // windows-1252's 0x80-0x9F; the five it leaves undefined keep their C1 code point
12121
+ "\u20AC\x81\u201A\u0192\u201E\u2026\u2020\u2021\u02C6\u2030\u0160\u2039\u0152\x8D\u017D\x8F\x90\u2018\u2019\u201C\u201D\u2022\u2013\u2014\u02DC\u2122\u0161\u203A\u0153\x9D\u017E\u0178"
12122
+ );
12123
+ var utf8 = new TextDecoder("utf-8", { fatal: true });
12124
+ function windows1252(bytes) {
12125
+ let out = "";
12126
+ for (let i = 0; i < bytes.length; i += 8192) {
12127
+ const chunk = bytes.subarray(i, i + 8192);
12128
+ const codes = new Array(chunk.length);
12129
+ for (let j = 0; j < chunk.length; j++) {
12130
+ const b = chunk[j];
12131
+ codes[j] = b >= 128 && b <= 159 ? LATIN1_HIGH.charCodeAt(b - 128) : b;
12132
+ }
12133
+ out += String.fromCharCode(...codes);
12134
+ }
12135
+ return out;
12136
+ }
12137
+ function utf16(bytes, bigEndian) {
12138
+ const n = bytes.length - bytes.length % 2;
12139
+ const b = Buffer.from(bytes.buffer, bytes.byteOffset, n);
12140
+ if (!bigEndian)
12141
+ return b.toString("utf16le");
12142
+ const swapped = Buffer.from(b);
12143
+ swapped.swap16();
12144
+ return swapped.toString("utf16le");
12145
+ }
12146
+ function decodeText(bytes) {
12147
+ if (bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 254)
12148
+ return utf16(bytes.subarray(2), false);
12149
+ if (bytes.length >= 2 && bytes[0] === 254 && bytes[1] === 255)
12150
+ return utf16(bytes.subarray(2), true);
12151
+ const body = bytes.length >= 3 && bytes[0] === 239 && bytes[1] === 187 && bytes[2] === 191 ? bytes.subarray(3) : bytes;
12152
+ try {
12153
+ return utf8.decode(body);
12154
+ } catch {
12155
+ return windows1252(body);
12156
+ }
12157
+ }
12158
+ function ignoreRules(text3, base) {
12159
+ const out = [];
12160
+ for (let line of text3.split(/\r?\n/)) {
12161
+ line = line.replace(/(?<!\\)\s+$/, "");
12162
+ if (!line || line.startsWith("#"))
12163
+ continue;
12164
+ let negate = false;
12165
+ if (line.startsWith("!")) {
12166
+ negate = true;
12167
+ line = line.slice(1);
12168
+ } else if (line.startsWith("\\!") || line.startsWith("\\#"))
12169
+ line = line.slice(1);
12170
+ const dirOnly = line.endsWith("/");
12171
+ if (dirOnly)
12172
+ line = line.slice(0, -1);
12173
+ if (!line)
12174
+ continue;
12175
+ const anchored = line.includes("/");
12176
+ try {
12177
+ out.push({ base, re: globMatcher(line.replace(/^\//, ""), !anchored), negate, dirOnly });
12178
+ } catch {
12179
+ }
12180
+ }
12181
+ return out;
12182
+ }
12183
+ function ignoredBy(rules, path, isDir) {
12184
+ let out = false;
12185
+ for (const r of rules) {
12186
+ if (r.dirOnly && !isDir)
12187
+ continue;
12188
+ if (r.base && !path.startsWith(`${r.base}/`))
12189
+ continue;
12190
+ const rel = r.base ? path.slice(r.base.length + 1) : path;
12191
+ if (r.re.test(rel))
12192
+ out = !r.negate;
12193
+ }
12194
+ return out;
12195
+ }
12196
+ var byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
12197
+ function folder(entries, rel, inherited, gitignore) {
12198
+ const rules = gitignore === void 0 ? inherited : [...inherited, ...ignoreRules(gitignore, rel)];
12199
+ const names = entries.map((e) => e.name);
12200
+ const kept = entries.filter((e) => !e.isSymbolicLink() && e.name !== ".git").sort(byName).map((e) => ({ e, path: rel ? `${rel}/${e.name}` : e.name }));
12201
+ return { rules, names, kept };
12202
+ }
12203
+ var hasGitignore = (entries) => entries.some((e) => e.name === ".gitignore" && e.isFile());
12204
+ async function walkRepo(root, visit, o = {}) {
12205
+ const max = o.max ?? Number.POSITIVE_INFINITY;
12206
+ let files = 0;
12207
+ let cut = false;
12208
+ const go = async (rel, above, inherited) => {
12209
+ const dir = rel ? join(root, ...rel.split("/")) : root;
12210
+ let entries;
12211
+ try {
12212
+ entries = await readdir(dir, { withFileTypes: true });
12213
+ } catch {
12214
+ return true;
12215
+ }
12216
+ const text3 = hasGitignore(entries) ? await readFile(join(dir, ".gitignore")).then(decodeText, () => void 0) : void 0;
12217
+ const { rules, names, kept } = folder(entries, rel, inherited, text3);
12218
+ for (const { e, path } of kept) {
12219
+ if (e.isDirectory()) {
12220
+ if (ignoredBy(rules, path, true) || o.skipFolder?.(above, e.name, names))
12221
+ continue;
12222
+ if (!await go(path, [...above, e.name], rules))
12223
+ return false;
12224
+ } else if (e.isFile()) {
12225
+ if (ignoredBy(rules, path, false))
12226
+ continue;
12227
+ if (files >= max) {
12228
+ cut = true;
12229
+ return false;
12230
+ }
12231
+ files++;
12232
+ if (await visit(path) === false)
12233
+ return false;
12234
+ }
12235
+ }
12236
+ return true;
12237
+ };
12238
+ await go("", [], []);
12239
+ return { files, cut };
12240
+ }
12241
+
10894
12242
  // packages/core/dist/log.js
10895
12243
  var LOG_MAX_BYTES = 5 * 1024 * 1024;
10896
12244
 
12245
+ // packages/core/dist/run-log.js
12246
+ var RUN_LOG_MAX_BYTES = 2 * 1024 * 1024;
12247
+ var RUN_SILENT_MS = 5 * 60 * 1e3;
12248
+ var DAY = 24 * 60 * 60 * 1e3;
12249
+
12250
+ // packages/core/dist/printer.js
12251
+ import { AsyncLocalStorage } from "node:async_hooks";
12252
+ var printer = new AsyncLocalStorage();
12253
+
10897
12254
  // packages/core/dist/zip-read.js
10898
12255
  var ZIP_LIMITS = {
10899
12256
  maxEntries: 1e4,
@@ -10918,7 +12275,8 @@ var BatchLink = z31.strictObject({
10918
12275
  var BatchQuestion = z31.strictObject({
10919
12276
  kind: z31.literal("question"),
10920
12277
  id: QuestionId,
10921
- before: QuestionAnswer.optional()
12278
+ before: QuestionAnswer.optional(),
12279
+ proposal: z31.string().min(1).max(65536).optional()
10922
12280
  });
10923
12281
  var BatchItem = z31.discriminatedUnion("kind", [BatchLink, BatchQuestion]);
10924
12282
  var DecisionBatch = z31.strictObject({
@@ -10978,19 +12336,38 @@ var QuestionProposal = z32.strictObject({
10978
12336
  at: IsoDateTime
10979
12337
  });
10980
12338
 
12339
+ // packages/core/dist/setup-edit.js
12340
+ import { isMap as isMap10, isNode, isScalar, isSeq as isSeq5, parseDocument as parseDocument10, stringify as stringify5 } from "yaml";
12341
+ var ADAPTER_KINDS = [
12342
+ "gitHost",
12343
+ "workTracker",
12344
+ "serviceDesk",
12345
+ "notify",
12346
+ "wiki",
12347
+ "design"
12348
+ ];
12349
+ function schemaTypes(kind) {
12350
+ const adapters = Runtime.shape.adapters.unwrap();
12351
+ return adapters.shape[kind]?.unwrap().options.find((o) => o.shape)?.shape?.type.options ?? [];
12352
+ }
12353
+ var ADAPTER_TYPES = Object.fromEntries(ADAPTER_KINDS.map((k) => [
12354
+ k,
12355
+ ["manual", ...schemaTypes(k).filter((t) => t !== "manual" && t !== "mock")]
12356
+ ]));
12357
+
10981
12358
  // packages/core/dist/specs.js
10982
12359
  import { parse as parse13 } from "yaml";
10983
12360
  var SPEC_CACHE_VERSION = `spec@${FLOW_SCHEMA_VERSION}.${SPEC_HEADER_SCHEMA_VERSION}`;
10984
12361
 
10985
12362
  // packages/core/dist/cancel.js
10986
- import { AsyncLocalStorage } from "node:async_hooks";
10987
- var store = new AsyncLocalStorage();
12363
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
12364
+ var store = new AsyncLocalStorage2();
10988
12365
 
10989
12366
  // packages/core/dist/decision-batches.js
10990
- import { parse as parse14, stringify as stringify5 } from "yaml";
12367
+ import { parse as parse14, stringify as stringify6 } from "yaml";
10991
12368
 
10992
12369
  // packages/core/dist/declared-links.js
10993
- import { isMap as isMap10, isScalar, isSeq as isSeq5, parseDocument as parseDocument10 } from "yaml";
12370
+ import { isMap as isMap11, isScalar as isScalar2, isSeq as isSeq6, parseDocument as parseDocument11 } from "yaml";
10994
12371
 
10995
12372
  // packages/core/dist/schema/reading-rules.js
10996
12373
  import { z as z33 } from "zod";
@@ -11354,8 +12731,20 @@ function globToRegExp(glob) {
11354
12731
  }
11355
12732
 
11356
12733
  // packages/sdk/dist/fs-repo.js
11357
- import { lstat, readdir, readFile, realpath, stat } from "node:fs/promises";
11358
- import { join, relative, resolve, sep } from "node:path";
12734
+ import { lstat, readFile as readFile2, realpath, stat } from "node:fs/promises";
12735
+ import { join as join2, resolve, sep } from "node:path";
12736
+
12737
+ // packages/sdk/dist/listing.js
12738
+ var LISTING = /* @__PURE__ */ Symbol.for("@maycombhq/sdk.listing");
12739
+ function listingOf(repo) {
12740
+ const v = repo[LISTING];
12741
+ return typeof v === "string" ? v : "";
12742
+ }
12743
+ function setListing(repo, listing) {
12744
+ Object.defineProperty(repo, LISTING, { value: listing, enumerable: false, configurable: true });
12745
+ }
12746
+
12747
+ // packages/sdk/dist/fs-repo.js
11359
12748
  var DEFAULT_IGNORES = [
11360
12749
  ".git",
11361
12750
  "node_modules",
@@ -11388,24 +12777,12 @@ function fsRepo(name, dir, commit, options = {}) {
11388
12777
  let cache;
11389
12778
  const sizes = /* @__PURE__ */ new Map();
11390
12779
  const skipped = /* @__PURE__ */ new Map();
11391
- async function walk(abs, out) {
11392
- const entries = await readdir(abs, { withFileTypes: true });
11393
- for (const e of entries) {
11394
- if (e.isSymbolicLink())
11395
- continue;
11396
- const full = join(abs, e.name);
11397
- if (e.isDirectory()) {
11398
- if (!ignore.has(e.name))
11399
- await walk(full, out);
11400
- } else if (e.isFile()) {
11401
- out.push(relative(root, full).split(sep).join("/"));
11402
- }
11403
- }
11404
- }
11405
12780
  async function allFiles() {
11406
12781
  if (!cache) {
11407
12782
  const out = [];
11408
- await walk(root, out);
12783
+ await walkRepo(root, async (p2) => void out.push(p2), {
12784
+ skipFolder: (_above, name2) => ignore.has(name2)
12785
+ });
11409
12786
  cache = out.sort();
11410
12787
  }
11411
12788
  return cache;
@@ -11414,7 +12791,7 @@ function fsRepo(name, dir, commit, options = {}) {
11414
12791
  if (path.startsWith("/") || /^[A-Za-z]:/.test(path) || path.includes("\\") || path.split("/").includes("..")) {
11415
12792
  throw new RepoReadError(`path must be repo-relative with forward slashes: ${path}`, path);
11416
12793
  }
11417
- const abs = join(root, ...path.split("/"));
12794
+ const abs = join2(root, ...path.split("/"));
11418
12795
  const info = await lstat(abs).catch(() => void 0);
11419
12796
  if (info?.isSymbolicLink())
11420
12797
  throw new RepoReadError(`symbolic links are not read: ${path}`, path);
@@ -11429,7 +12806,7 @@ function fsRepo(name, dir, commit, options = {}) {
11429
12806
  throw new RepoReadError(`file is larger than ${maxBytes} bytes: ${path}`, path);
11430
12807
  return abs;
11431
12808
  }
11432
- return {
12809
+ const handle = {
11433
12810
  name,
11434
12811
  commit,
11435
12812
  async *listFiles(globs) {
@@ -11438,7 +12815,7 @@ function fsRepo(name, dir, commit, options = {}) {
11438
12815
  if (!matchers.some((m) => m.test(p2)))
11439
12816
  continue;
11440
12817
  if (!sizes.has(p2))
11441
- sizes.set(p2, (await stat(join(root, ...p2.split("/"))).catch(() => void 0))?.size ?? 0);
12818
+ sizes.set(p2, (await stat(join2(root, ...p2.split("/"))).catch(() => void 0))?.size ?? 0);
11442
12819
  const bytes = sizes.get(p2);
11443
12820
  if (bytes > maxBytes) {
11444
12821
  skipped.set(p2, bytes);
@@ -11452,16 +12829,17 @@ function fsRepo(name, dir, commit, options = {}) {
11452
12829
  return [...skipped].sort(([a], [b]) => a < b ? -1 : 1).map(([path, bytes]) => ({ path, bytes }));
11453
12830
  },
11454
12831
  async readText(path) {
11455
- const text3 = await readFile(await safePath(path), "utf8");
11456
- return text3.charCodeAt(0) === 65279 ? text3.slice(1) : text3;
12832
+ return decodeText(await readFile2(await safePath(path)));
11457
12833
  }
11458
12834
  };
12835
+ setListing(handle, JSON.stringify({ ignore: [...ignore].sort(), maxFileBytes: maxBytes, gitignore: true }));
12836
+ return handle;
11459
12837
  }
11460
12838
 
11461
12839
  // packages/sdk/dist/cache.js
11462
12840
  import { createHash as createHash3 } from "node:crypto";
11463
- import { mkdir, readdir as readdir2, readFile as readFile2, rename, rm, writeFile } from "node:fs/promises";
11464
- import { join as join2 } from "node:path";
12841
+ import { mkdir, readdir as readdir2, readFile as readFile3, rename, rm, writeFile } from "node:fs/promises";
12842
+ import { join as join3 } from "node:path";
11465
12843
  var sha256 = (s) => createHash3("sha256").update(s).digest("hex");
11466
12844
  function cacheKeyHash(key) {
11467
12845
  return sha256(JSON.stringify([
@@ -11500,7 +12878,7 @@ function fsScanCache(dir) {
11500
12878
  const h = cacheKeyHash(key);
11501
12879
  return {
11502
12880
  h,
11503
- path: join2(dir, key.repo, key.commit, `${key.extractor}@${key.version}.${h.slice(0, 16)}.json`)
12881
+ path: join3(dir, key.repo, key.commit, `${key.extractor}@${key.version}.${h.slice(0, 16)}.json`)
11504
12882
  };
11505
12883
  };
11506
12884
  return {
@@ -11508,7 +12886,7 @@ function fsScanCache(dir) {
11508
12886
  const { h, path } = fileFor(key);
11509
12887
  let file;
11510
12888
  try {
11511
- file = JSON.parse(await readFile2(path, "utf8"));
12889
+ file = JSON.parse(await readFile3(path, "utf8"));
11512
12890
  } catch {
11513
12891
  return void 0;
11514
12892
  }
@@ -11534,7 +12912,7 @@ function fsScanCache(dir) {
11534
12912
  checksum: sha256(JSON.stringify(value)),
11535
12913
  value
11536
12914
  };
11537
- await mkdir(join2(path, ".."), { recursive: true });
12915
+ await mkdir(join3(path, ".."), { recursive: true });
11538
12916
  const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
11539
12917
  await writeFile(tmp, JSON.stringify(file), "utf8");
11540
12918
  await rename(tmp, path);
@@ -11546,13 +12924,13 @@ function fsScanCache(dir) {
11546
12924
  let removed = 0;
11547
12925
  let commits;
11548
12926
  try {
11549
- commits = await readdir2(join2(dir, repo));
12927
+ commits = await readdir2(join3(dir, repo));
11550
12928
  } catch {
11551
12929
  return 0;
11552
12930
  }
11553
12931
  for (const c of commits) {
11554
12932
  if (!keep.has(c)) {
11555
- await rm(join2(dir, repo, c), { recursive: true, force: true });
12933
+ await rm(join3(dir, repo, c), { recursive: true, force: true });
11556
12934
  removed++;
11557
12935
  }
11558
12936
  }
@@ -11657,7 +13035,10 @@ async function scanWith(options) {
11657
13035
  options.configFor?.(extractor) ?? "",
11658
13036
  JSON.stringify(options.repoInfo ?? {}),
11659
13037
  // A changed framework model means a different reading of the same code.
11660
- options.frameworks?.length ? JSON.stringify(options.frameworks) : ""
13038
+ options.frameworks?.length ? JSON.stringify(options.frameworks) : "",
13039
+ // Review round 49: the same commit listed another way (scan-settings exclusions, the
13040
+ // folders left out, the size limit) gives the extractor other files.
13041
+ listingOf(repo)
11661
13042
  ].join("|")
11662
13043
  };
11663
13044
  try {
@@ -11746,8 +13127,8 @@ async function scanWith(options) {
11746
13127
 
11747
13128
  // packages/sdk/dist/sandbox.js
11748
13129
  import { createHash as createHash4 } from "node:crypto";
11749
- import { readFile as readFile3 } from "node:fs/promises";
11750
- import { join as join3 } from "node:path";
13130
+ import { readFile as readFile4 } from "node:fs/promises";
13131
+ import { join as join4 } from "node:path";
11751
13132
  import { Worker } from "node:worker_threads";
11752
13133
  var PLUGIN_EXTRACTOR_PREFIX = "plugin-";
11753
13134
  var MAX_RECORDS = 1e5;
@@ -11759,7 +13140,7 @@ async function readPinnedEntry(dir, manifest) {
11759
13140
  return { ok: false, message: "isn't pinned: run atticus plugin pin once it is reviewed" };
11760
13141
  let source;
11761
13142
  try {
11762
- source = await readFile3(join3(dir, ...manifest.entry.split("/")), "utf8");
13143
+ source = await readFile4(join4(dir, ...manifest.entry.split("/")), "utf8");
11763
13144
  } catch (e) {
11764
13145
  return { ok: false, message: `can't read ${manifest.entry}: ${e.message}` };
11765
13146
  }