@iowarp/clio-coder 0.4.4 → 0.4.5

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 (555) hide show
  1. package/CHANGELOG.md +92 -2
  2. package/CONTRIBUTING.md +25 -15
  3. package/README.md +340 -27
  4. package/dist/{acp-WNAYYF4F.js → acp-H3CU2HBQ.js} +25 -24
  5. package/dist/{agents-3OKXHLOI.js → agents-IXQQZ7BD.js} +77 -77
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-VKNNMGPU.js → auth-R7KYF7N3.js} +38 -38
  8. package/dist/builtins-CRFDQUVP.js +22 -0
  9. package/dist/{chunk-TQAHXW6Y.js → chunk-22PQ4TX4.js} +4 -4
  10. package/dist/{chunk-NEDJ26B5.js → chunk-2GPGAE5W.js} +6 -51
  11. package/dist/{chunk-IKCO5N3L.js → chunk-2QPI3TR3.js} +3 -3
  12. package/dist/{chunk-HRQMFLJP.js → chunk-32KJPXAM.js} +6 -6
  13. package/dist/{chunk-65DEGPJ6.js → chunk-3A3CUMKA.js} +6 -4
  14. package/dist/{chunk-JCI2ROMZ.js → chunk-3T4DXWP6.js} +7 -7
  15. package/dist/{chunk-DR52UMZW.js → chunk-3UW3KU4A.js} +2 -2
  16. package/dist/{chunk-6Q3CYFD3.js → chunk-4SVIVOMC.js} +184 -33
  17. package/dist/{chunk-W54I7H25.js → chunk-5A6XR3RJ.js} +44 -19
  18. package/dist/{chunk-YPC6ZR5L.js → chunk-5CMARGPF.js} +119 -5
  19. package/dist/{chunk-KXDSS5WJ.js → chunk-5CY4Q6QI.js} +4 -4
  20. package/dist/{chunk-I2DWJ4GM.js → chunk-5DDOTTG4.js} +54 -42
  21. package/dist/{chunk-D4CJV46V.js → chunk-5GZICIYO.js} +3 -3
  22. package/dist/{chunk-4IUZQIJ3.js → chunk-5PHVPU4G.js} +2 -2
  23. package/dist/{chunk-3ODX73FK.js → chunk-5VTJP36Q.js} +4 -4
  24. package/dist/{chunk-54X7T7DK.js → chunk-5ZMXGW7P.js} +79 -7
  25. package/dist/chunk-5ZSZEYJK.js +119 -0
  26. package/dist/{chunk-IXIY2H4R.js → chunk-633EXGZA.js} +5 -5
  27. package/dist/{chunk-CUSRQKPU.js → chunk-6CDNRHWH.js} +299 -89
  28. package/dist/{chunk-EBY63B7G.js → chunk-6EXUUOSN.js} +2 -2
  29. package/dist/{chunk-SVNXH4L2.js → chunk-6ICZKDUC.js} +2 -2
  30. package/dist/{chunk-JEIYHLOR.js → chunk-6SYEGZI3.js} +12 -12
  31. package/dist/{chunk-DQOVN6KV.js → chunk-6YA46L5A.js} +4 -4
  32. package/dist/{chunk-NZMNUPZZ.js → chunk-77CZRFTE.js} +3 -3
  33. package/dist/{chunk-6PAZTBPA.js → chunk-7HBHHVCK.js} +15 -6
  34. package/dist/{chunk-25QBEXRS.js → chunk-7TKWWPD7.js} +5 -4
  35. package/dist/{chunk-2VTFPG5O.js → chunk-7WLRF2U5.js} +2 -2
  36. package/dist/chunk-7WUZEB2M.js +165 -0
  37. package/dist/{chunk-3UUXNFEX.js → chunk-7YJWEF2L.js} +61 -34
  38. package/dist/{chunk-3EBYEESD.js → chunk-A46ILRS2.js} +5 -5
  39. package/dist/{chunk-UOIZ7DA4.js → chunk-AP7HDJOP.js} +2 -2
  40. package/dist/{chunk-APJ265NV.js → chunk-B5GGDIHT.js} +146 -146
  41. package/dist/{chunk-PMZVFWSR.js → chunk-B5ZTR6KZ.js} +2 -2
  42. package/dist/{chunk-I5FWO7L5.js → chunk-B6UM3OZC.js} +2 -2
  43. package/dist/{chunk-2CU2H6KE.js → chunk-BBV5TKE6.js} +5 -5
  44. package/dist/{chunk-4O6MANBS.js → chunk-BS4GAMUB.js} +14 -10
  45. package/dist/{chunk-S66XZJOF.js → chunk-C27U2TYG.js} +2 -2
  46. package/dist/{chunk-QZWQA4DE.js → chunk-CBSKDFWL.js} +3 -3
  47. package/dist/{chunk-2LEAKD4C.js → chunk-CKK25WN3.js} +3 -3
  48. package/dist/{chunk-BYP5D4HI.js → chunk-CTTI7G3T.js} +2 -2
  49. package/dist/{chunk-XAKHZX5N.js → chunk-CVDAFGPW.js} +4 -4
  50. package/dist/{chunk-RKKLTLYB.js → chunk-CXQ37WJH.js} +3 -3
  51. package/dist/{chunk-GTUD2WMY.js → chunk-DBREN25X.js} +44 -9
  52. package/dist/{chunk-YNFKXPEC.js → chunk-DIMRLNIC.js} +35 -66
  53. package/dist/{chunk-NDDGJUXD.js → chunk-DNCE23JJ.js} +2 -2
  54. package/dist/{chunk-HVDIIIQW.js → chunk-DNHVRBH4.js} +3 -3
  55. package/dist/{chunk-XULDXHTN.js → chunk-DRD2A54W.js} +102 -50
  56. package/dist/{chunk-D7E7WCDF.js → chunk-DVNAPPXU.js} +2 -2
  57. package/dist/{chunk-YXLYO42X.js → chunk-DXVMLM3Z.js} +3 -2
  58. package/dist/{chunk-5MEZN6CB.js → chunk-DZK63TZJ.js} +6 -6
  59. package/dist/{chunk-IGLP3ODT.js → chunk-E3BQTQUP.js} +15 -15
  60. package/dist/{chunk-IWHMRKLL.js → chunk-E3LEPLQ2.js} +2 -2
  61. package/dist/{chunk-3R73A4XB.js → chunk-ECBHH7LU.js} +3 -3
  62. package/dist/chunk-ECOMVOHP.js +139 -0
  63. package/dist/chunk-EFSEIZE6.js +56 -0
  64. package/dist/{chunk-FEAXX7B6.js → chunk-EHCPSZJF.js} +4 -4
  65. package/dist/{chunk-4NSRCOYP.js → chunk-EHOSNVVM.js} +3 -2
  66. package/dist/{chunk-7UGL4MB5.js → chunk-EQEJJ53P.js} +10 -10
  67. package/dist/{chunk-GWZNEVM2.js → chunk-EWD5P3GK.js} +9 -9
  68. package/dist/{chunk-6UINWWS6.js → chunk-F34AR6O3.js} +14 -14
  69. package/dist/{chunk-GHS5EBTQ.js → chunk-FKIOX6DS.js} +29 -20
  70. package/dist/{chunk-HAXOFFRH.js → chunk-FQOOGXBH.js} +7 -7
  71. package/dist/{chunk-Y55JBDO5.js → chunk-FSTIBAGM.js} +38 -23
  72. package/dist/{chunk-ZTJUVLTU.js → chunk-FXFVDPWY.js} +2 -2
  73. package/dist/{chunk-XPLRXC72.js → chunk-GD55RTIW.js} +3 -3
  74. package/dist/{chunk-5B2AEOW5.js → chunk-GH5ZR6JP.js} +472 -472
  75. package/dist/{chunk-TOIVGRUX.js → chunk-GJ24ODAX.js} +5 -5
  76. package/dist/{chunk-QUFRYSWI.js → chunk-GNQRWTMY.js} +129 -48
  77. package/dist/{chunk-5ICU3EUH.js → chunk-GVYWZNRK.js} +5 -5
  78. package/dist/{chunk-GX5WYQO4.js → chunk-GXCCHKN6.js} +6 -6
  79. package/dist/{chunk-K6T2ZAMZ.js → chunk-HGSLRG33.js} +6 -6
  80. package/dist/{chunk-26QSH3EJ.js → chunk-HHVJNVUJ.js} +5 -5
  81. package/dist/{chunk-F4EKGO4N.js → chunk-HL26ADLH.js} +4 -2
  82. package/dist/{chunk-JT2RFCC5.js → chunk-HR3HPQ76.js} +5 -5
  83. package/dist/{chunk-ID64D7PE.js → chunk-HXHFDHB6.js} +24 -24
  84. package/dist/{chunk-ELWDPP3Y.js → chunk-I7VLWRK2.js} +8 -8
  85. package/dist/{chunk-6OSVSQL5.js → chunk-ICO4TQ2F.js} +7 -5
  86. package/dist/{chunk-SZAA6XDG.js → chunk-IFDRAD6F.js} +2 -2
  87. package/dist/{chunk-72YIHOZQ.js → chunk-ILJ7DWGE.js} +9 -9
  88. package/dist/{chunk-2JH2WHGE.js → chunk-J2FYEQ5L.js} +4 -4
  89. package/dist/{chunk-BMS5RKQY.js → chunk-JABWPKFY.js} +3 -3
  90. package/dist/{chunk-QDC3K2U3.js → chunk-K2BLQC5E.js} +3 -3
  91. package/dist/{chunk-AUPNRN7C.js → chunk-K2HL3GBL.js} +4 -4
  92. package/dist/{chunk-2ASED4PZ.js → chunk-K6RDB7IA.js} +26 -26
  93. package/dist/{chunk-FFUPXJC4.js → chunk-KDWLXVMN.js} +23 -24
  94. package/dist/{chunk-OZNBF4L3.js → chunk-KECNXMDE.js} +2 -2
  95. package/dist/{chunk-6QOTUPRG.js → chunk-KF6GFW6O.js} +66 -18
  96. package/dist/{chunk-BTK3SSSK.js → chunk-KMF54VH3.js} +2 -2
  97. package/dist/chunk-KPRLAMP4.js +32 -0
  98. package/dist/{chunk-ECH6PKUQ.js → chunk-KQ6IDQIB.js} +2 -2
  99. package/dist/{chunk-3UNOLWNZ.js → chunk-KTFSFCVN.js} +20 -9
  100. package/dist/{chunk-57XXR6DR.js → chunk-KYKNBD4Y.js} +24 -23
  101. package/dist/{chunk-IRXAATOX.js → chunk-L4N3DWNW.js} +3 -3
  102. package/dist/{chunk-LCGCVYZ4.js → chunk-LQTKDAUO.js} +2 -2
  103. package/dist/{chunk-U6TMQNSI.js → chunk-LTR5QCLS.js} +4 -4
  104. package/dist/chunk-LUL5Z66S.js +221 -0
  105. package/dist/{chunk-ELZVTCGV.js → chunk-LVFANMOH.js} +151 -327
  106. package/dist/{chunk-H7IXIC72.js → chunk-LY4N4TTL.js} +17 -3
  107. package/dist/{chunk-VKPAQYEB.js → chunk-LZBMXNLP.js} +5 -5
  108. package/dist/{chunk-UL3WSD3F.js → chunk-M4KFUXS7.js} +2 -2
  109. package/dist/{chunk-NXYCB2VD.js → chunk-M6TAYK66.js} +6 -6
  110. package/dist/{chunk-NEKRRTYW.js → chunk-MC3JSVR6.js} +2 -2
  111. package/dist/{chunk-CFGTUFWB.js → chunk-MCJKEGHO.js} +2 -2
  112. package/dist/{chunk-DXKJURES.js → chunk-MDU3C27C.js} +10 -7
  113. package/dist/{chunk-6XLNIQDB.js → chunk-MYI32N4R.js} +2 -2
  114. package/dist/{chunk-3GY4F45V.js → chunk-NC4KV7EL.js} +6 -6
  115. package/dist/{chunk-LLXSDWXS.js → chunk-NF3BK5WR.js} +5 -5
  116. package/dist/chunk-NTK3WTHM.js +141 -0
  117. package/dist/{chunk-GYV6VZOC.js → chunk-NTTS3O53.js} +2 -2
  118. package/dist/{chunk-RZDWV63N.js → chunk-NY6IWDVU.js} +6 -6
  119. package/dist/{chunk-XXYSBZIQ.js → chunk-O2RQ7LCK.js} +4 -4
  120. package/dist/{chunk-4BJ5BYCE.js → chunk-O3VV6IVK.js} +2 -2
  121. package/dist/{chunk-W6GROXXM.js → chunk-O5F25NIE.js} +2 -2
  122. package/dist/{chunk-NXIMQY5W.js → chunk-ODUTYZIU.js} +5 -5
  123. package/dist/{chunk-LTIKRKFL.js → chunk-ONRTXOZY.js} +4 -4
  124. package/dist/{chunk-KFV5L5SK.js → chunk-OQM5IVJY.js} +118 -232
  125. package/dist/{chunk-XRZT5WY5.js → chunk-P5SC4DLJ.js} +4 -4
  126. package/dist/{chunk-R6Q67RJH.js → chunk-PECBKCDK.js} +34 -6
  127. package/dist/{chunk-33YXPOE3.js → chunk-PPEZJWUG.js} +2 -2
  128. package/dist/{chunk-RXTN6AKH.js → chunk-PWWSIB2A.js} +5 -5
  129. package/dist/{chunk-2STGEDFV.js → chunk-QEQISF75.js} +2 -2
  130. package/dist/{chunk-3DPEIQKN.js → chunk-QH3ZTUOA.js} +2 -2
  131. package/dist/{chunk-YAKGTXEV.js → chunk-QRFXEO6Y.js} +2 -2
  132. package/dist/{chunk-35MSIRKH.js → chunk-QUIJZSDW.js} +2 -2
  133. package/dist/{chunk-HHV2GANA.js → chunk-R2P2U3ZS.js} +2 -2
  134. package/dist/{chunk-2DSOYNFC.js → chunk-R6MAYTMS.js} +7 -7
  135. package/dist/{chunk-JQLNNIKT.js → chunk-R6MICQYU.js} +6 -6
  136. package/dist/{chunk-NAI6ZFCY.js → chunk-RLTT5GVY.js} +122 -11
  137. package/dist/{chunk-DT3LWJOB.js → chunk-RXIOCVBZ.js} +24 -6
  138. package/dist/{chunk-N56KALIC.js → chunk-S32UQ5GL.js} +61 -34
  139. package/dist/{chunk-UEPWCCTY.js → chunk-SBZX6ARC.js} +12 -12
  140. package/dist/chunk-SD7SHNDW.js +15 -0
  141. package/dist/{chunk-NRO2BJRH.js → chunk-SDWNDICN.js} +10235 -4015
  142. package/dist/{chunk-UXCU4E3T.js → chunk-SE4ZKILO.js} +6 -6
  143. package/dist/chunk-SL2RDHKO.js +19 -0
  144. package/dist/{chunk-NUGM5KR6.js → chunk-SRCEQKQS.js} +2 -2
  145. package/dist/{chunk-OMQNJVKW.js → chunk-SRZOW5L2.js} +43 -13
  146. package/dist/{chunk-3M6DQK6S.js → chunk-T334FW2H.js} +7 -7
  147. package/dist/{chunk-V76WTFTW.js → chunk-T52TPHYC.js} +6 -6
  148. package/dist/{chunk-I7XBWTYH.js → chunk-T53XI6I7.js} +5 -5
  149. package/dist/{chunk-2ZSONWVL.js → chunk-T7FDXNRU.js} +13 -13
  150. package/dist/{chunk-JSD46VO2.js → chunk-TEG3RYVZ.js} +43 -36
  151. package/dist/{chunk-3I7MS7N2.js → chunk-TK2BMCBZ.js} +2 -2
  152. package/dist/{chunk-5OIVVPHF.js → chunk-TN5FW4XY.js} +13 -6
  153. package/dist/{chunk-75W7L2E2.js → chunk-TZ7MFRG4.js} +1041 -162
  154. package/dist/{chunk-36CT5VVL.js → chunk-U2JOLB7O.js} +126 -77
  155. package/dist/{chunk-LL4KHSZI.js → chunk-U2MSJ57E.js} +2 -2
  156. package/dist/{chunk-FTMGRKEF.js → chunk-U44YYLVV.js} +4 -4
  157. package/dist/{chunk-YECAMM3D.js → chunk-U7H5WRG5.js} +5 -5
  158. package/dist/{chunk-RQCKCSRL.js → chunk-U7VQ4NI4.js} +22 -22
  159. package/dist/{chunk-5TUB6SLS.js → chunk-UFYNOQK4.js} +7 -7
  160. package/dist/{chunk-R346GLFC.js → chunk-UHW5V7HC.js} +2 -2
  161. package/dist/{chunk-USR47QNF.js → chunk-UL36QJX6.js} +14 -14
  162. package/dist/{chunk-VIA6RFQZ.js → chunk-UQIVHSE4.js} +4 -4
  163. package/dist/{chunk-RAY4OVGZ.js → chunk-URBGEOH3.js} +5 -5
  164. package/dist/chunk-USZA7GWL.js +341 -0
  165. package/dist/{chunk-YD5GIKET.js → chunk-UTUNT5QL.js} +48 -579
  166. package/dist/{chunk-ZA4VCIGV.js → chunk-UUQ5G6EZ.js} +60 -41
  167. package/dist/{chunk-23L32XTI.js → chunk-UXAC2FX4.js} +68 -39
  168. package/dist/{chunk-VG7TBQIY.js → chunk-V552WL53.js} +68 -4
  169. package/dist/{chunk-BWH6N36D.js → chunk-VHKTOLEW.js} +272 -42
  170. package/dist/{chunk-EXLD33WO.js → chunk-VLPTKCKT.js} +24 -9
  171. package/dist/{chunk-336NSSKI.js → chunk-VNBICSS2.js} +2 -2
  172. package/dist/{chunk-VAVR4IJY.js → chunk-VQD7NH7Z.js} +3 -3
  173. package/dist/{chunk-LBMZMYH2.js → chunk-W2RJEH6Q.js} +3 -3
  174. package/dist/{chunk-7CR24IG7.js → chunk-WDV62RKY.js} +2 -2
  175. package/dist/{chunk-S6PYF2XF.js → chunk-WFKDPU7U.js} +4 -4
  176. package/dist/{chunk-BJVFZO5U.js → chunk-WJIMKGD6.js} +7 -7
  177. package/dist/{chunk-5636DCO5.js → chunk-WLMSOT73.js} +59 -12
  178. package/dist/{chunk-MXHC5QYU.js → chunk-WTQGRBHV.js} +5 -144
  179. package/dist/chunk-WXA2CFJO.js +23 -0
  180. package/dist/{chunk-QSNYB6ZV.js → chunk-XCUDZQLX.js} +3 -3
  181. package/dist/{chunk-4M6Z5QVF.js → chunk-XXBQKW32.js} +11 -11
  182. package/dist/{chunk-OEJSLEPW.js → chunk-YEJIG7LN.js} +332 -332
  183. package/dist/chunk-YGDMBK7O.js +567 -0
  184. package/dist/{chunk-4WR7VSYB.js → chunk-YYB3MC65.js} +23 -9
  185. package/dist/{chunk-2IR2NMPA.js → chunk-ZIDFQJRB.js} +2 -2
  186. package/dist/{chunk-Q4WO54TA.js → chunk-ZMZQEBKI.js} +14 -14
  187. package/dist/{chunk-6EJMN2Y3.js → chunk-ZTNFYMIO.js} +2 -2
  188. package/dist/{chunk-WEPFGWHJ.js → chunk-ZZFWWYLX.js} +2 -2
  189. package/dist/cli/index.js +44 -44
  190. package/dist/clio-5I2IBFYL.js +26 -0
  191. package/dist/{code-nav-IJR2DBPR.js → code-nav-YXIAEZVS.js} +48 -32
  192. package/dist/codewiki/build-worker.js +76 -29
  193. package/dist/{compile-cache-OQAVB7Y5.js → compile-cache-WJEPUZEJ.js} +4 -4
  194. package/dist/{components-2TGAI2RC.js → components-TNIKXCBH.js} +13 -13
  195. package/dist/{config-IUA6OYNS.js → config-Y2JDJ3JJ.js} +210 -124
  196. package/dist/configure-SML6UBZ5.js +55 -0
  197. package/dist/{context-4MPR7WKB.js → context-P5YSEO55.js} +125 -121
  198. package/dist/{context-2DKHWH2T.js → context-QQ53HSGJ.js} +91 -62
  199. package/dist/{context-BOYF5EJM.js → context-S2EEC3EJ.js} +62 -31
  200. package/dist/context-clear-TMEQCOTH.js +183 -0
  201. package/dist/{context-index-HNG3MOME.js → context-index-HP2JFUWA.js} +13 -11
  202. package/dist/{context-map-COB37XXN.js → context-map-INTXD54D.js} +71 -21
  203. package/dist/{context-working-set-3I3FYX6Y.js → context-working-set-CNLSQN5K.js} +31 -31
  204. package/dist/detail-5572VLBO.js +114 -0
  205. package/dist/{dispatch-runner-RJ5I2F2O.js → dispatch-runner-FRHD6P2O.js} +191 -116
  206. package/dist/{docs-SPOV3BAN.js → docs-BL7ROUFN.js} +4 -4
  207. package/dist/{doctor-DKICC2SN.js → doctor-N3LCM2LG.js} +58 -58
  208. package/dist/{eval-OQOQUDHK.js → eval-BUU3ZOUZ.js} +473 -168
  209. package/dist/{eval-inventory-Y6QRFOH5.js → eval-inventory-QOYZERXJ.js} +7 -7
  210. package/dist/evidence-DTGEN456.js +224 -0
  211. package/dist/{evidence-4DQ25GUQ.js → evidence-SQ5DNFEN.js} +110 -94
  212. package/dist/{evolve-GSS52E5J.js → evolve-IJNUFZDS.js} +107 -91
  213. package/dist/{extensions-G7MFLYHT.js → extensions-YVRHX6ZI.js} +16 -16
  214. package/dist/{fleet-Q37YHHAQ.js → fleet-ZNNVSYFO.js} +147 -147
  215. package/dist/{fleet-commands-G7E4N7SM.js → fleet-commands-5YE7NPJL.js} +27 -26
  216. package/dist/{fleet-decisions-O7M6QBA2.js → fleet-decisions-3SBSCTCW.js} +16 -15
  217. package/dist/{fleet-graph-TOUBW6OW.js → fleet-graph-6HHPWF5T.js} +39 -38
  218. package/dist/{fleet-inspect-SW33JJNI.js → fleet-inspect-JEYMGCGC.js} +107 -91
  219. package/dist/{fleet-new-RDVJLHHH.js → fleet-new-RCKGSRDV.js} +3 -3
  220. package/dist/{fleet-preflight-CV2655TW.js → fleet-preflight-QRSHIIDE.js} +10 -9
  221. package/dist/{fleet-validate-KESZX2YH.js → fleet-validate-4PM4GDDL.js} +46 -42
  222. package/dist/{fleet-verify-UQPMTVE3.js → fleet-verify-NJDTHTO3.js} +105 -89
  223. package/dist/fleet-view-UP2BWQQY.js +117 -0
  224. package/dist/{init-PXEXQSBF.js → init-S3GZQ5ZF.js} +123 -123
  225. package/dist/{install-NKNG7KD4.js → install-3RZDDP23.js} +5 -5
  226. package/dist/{interop-ZG5T62U3.js → interop-YOTGXFJM.js} +25 -25
  227. package/dist/inventory-K2OZ36YJ.js +117 -0
  228. package/dist/{library-B2W4N74O.js → library-GJI6W6OK.js} +45 -44
  229. package/dist/{memory-YCANYS5A.js → memory-OQOXQGYD.js} +107 -93
  230. package/dist/{models-GERTU3YI.js → models-3IK2Y5WE.js} +63 -62
  231. package/dist/{monitor-CPNIUULB.js → monitor-FTJLTKCQ.js} +136 -107
  232. package/dist/{orchestrator-J4BSH4WQ.js → orchestrator-N47O7SFD.js} +1159 -697
  233. package/dist/{panes-BOHAEGYC.js → panes-7BTYH3XQ.js} +8 -8
  234. package/dist/{panes-NXSLDQZ2.js → panes-WPOMEMRH.js} +22 -22
  235. package/dist/{paths-VSUWNC22.js → paths-J3KN7UAO.js} +12 -12
  236. package/dist/preload-65U34NG6.js +115 -0
  237. package/dist/{registry-LG64LTF4.js → registry-DESGAXWK.js} +3 -3
  238. package/dist/{reset-TNWTB5LU.js → reset-MUVQDLNL.js} +20 -20
  239. package/dist/{resources-4PXNMD5G.js → resources-LM76COAO.js} +41 -40
  240. package/dist/{run-D6XJ34CN.js → run-3VFZQ33N.js} +162 -156
  241. package/dist/{share-2NWMJJEE.js → share-4JUB4BL7.js} +43 -42
  242. package/dist/{skills-KR7WON5G.js → skills-S36AAJHU.js} +47 -46
  243. package/dist/{skills-eval-O2ZNOLDS.js → skills-eval-G6T57L7M.js} +127 -107
  244. package/dist/{skills-inventory-ZZOUBK7O.js → skills-inventory-WLM46PJH.js} +41 -40
  245. package/dist/slash-commands-GBARG3Y7.js +91 -0
  246. package/dist/{steer-XA25PSCS.js → steer-S7D7IKPU.js} +7 -7
  247. package/dist/{support-7EMVWYG2.js → support-5VAEC32W.js} +14 -14
  248. package/dist/{targets-OMH2XCSN.js → targets-N5REUETU.js} +145 -94
  249. package/dist/tasks-6BVY5YZF.js +36 -0
  250. package/dist/{terminal-lease-C2J3JYRE.js → terminal-lease-57UEOJKS.js} +12 -11
  251. package/dist/tools-6OCQ6SVB.js +28 -0
  252. package/dist/{trace-FXMXUZUF.js → trace-JHLXWUMN.js} +18 -17
  253. package/dist/{tree-sitter-HGKH6LG4.js → tree-sitter-AQUUOSYM.js} +6 -6
  254. package/dist/{tui-primitives-K5PASC3O.js → tui-primitives-RCY2HN7G.js} +3 -3
  255. package/dist/{uninstall-HALS6BLF.js → uninstall-FXYMFFRT.js} +17 -17
  256. package/dist/{upgrade-MS72RJEP.js → upgrade-4HD5HAIV.js} +40 -39
  257. package/dist/{usage-NHG6MCJM.js → usage-4GWM2WWP.js} +136 -105
  258. package/dist/{verifiers-7AUNVXDY.js → verifiers-GSKWKWVG.js} +28 -27
  259. package/dist/verify-3AS3ULCY.js +30 -0
  260. package/dist/{version-KGEG7EPO.js → version-RFPKO6T7.js} +4 -4
  261. package/dist/{web-fetch-V4FKSDAV.js → web-fetch-MQN4FH3X.js} +169 -18
  262. package/dist/wiki-generate-7BV7XWIY.js +614 -0
  263. package/dist/{with-panes-BDQEWBRT.js → with-panes-OFTNAR4Y.js} +34 -20
  264. package/dist/worker/entry.js +99 -88
  265. package/dist/{workspace-ZJ6BFM3Q.js → workspace-DZ7JADBG.js} +6 -6
  266. package/docs/README.md +7 -6
  267. package/docs/architecture/acp.md +10 -0
  268. package/docs/architecture/architecture.md +5 -5
  269. package/docs/architecture/context-engine.md +44 -59
  270. package/docs/architecture/context-working-set.md +7 -9
  271. package/docs/architecture/dispatch-architecture-rationale.md +1 -1
  272. package/docs/architecture/evidence-and-memory.md +10 -0
  273. package/docs/architecture/pi-boundary.md +37 -7
  274. package/docs/architecture/prompt-envelope-and-tools.md +7 -7
  275. package/docs/architecture/session-lifecycle.md +4 -4
  276. package/docs/architecture/worker-dispatch-mechanics.md +4 -0
  277. package/docs/guide/commands-and-modes.md +49 -36
  278. package/docs/guide/configuration-and-targets.md +7 -2
  279. package/docs/guide/configuration-reference.md +13 -3
  280. package/docs/guide/environment-variables.md +6 -2
  281. package/docs/guide/fleet-dispatch.md +12 -0
  282. package/docs/guide/installation-and-lifecycle.md +35 -9
  283. package/docs/guide/proactive-memory.md +1 -1
  284. package/docs/guide/skills-marketplace.md +11 -3
  285. package/docs/guide/tool-usage.md +9 -2
  286. package/docs/process/development-pipeline.md +10 -10
  287. package/docs/process/documentation-guide.md +2 -2
  288. package/docs/process/eval-runner.md +15 -0
  289. package/docs/process/evals-internal.md +1 -1
  290. package/docs/process/release-cut-checklist.md +6 -6
  291. package/evals/README.md +4 -0
  292. package/evals/behavioral-corpus-grader.mjs +147 -14
  293. package/evals/behavioral-model-negative-control.yaml +1 -0
  294. package/evals/behavioral-model.yaml +266 -1
  295. package/evals/fixtures/docs-retrieval.json +102 -0
  296. package/evals/fixtures/scalar-decision.json +17 -0
  297. package/evals/fixtures/scout-citation-pipeline.json +55 -0
  298. package/evals/fixtures/source-explanation.json +74 -0
  299. package/evals/fixtures/tool-arguments.json +18 -0
  300. package/evals/fixtures/tool-surface/read.txt +4 -0
  301. package/evals/fixtures/tool-surface/subdir/keep.txt +1 -0
  302. package/evals/no-edit-memory-grader.mjs +149 -0
  303. package/evals/scalar-decision-grader.py +41 -0
  304. package/evals/scalar-decision-machinery.ts +145 -0
  305. package/evals/source-explanation-grader.mjs +118 -0
  306. package/evals/tool-surface-grader.mjs +53 -0
  307. package/evals/tool-surface-model.yaml +274 -0
  308. package/package.json +14 -14
  309. package/skills/README.md +6 -6
  310. package/skills/registry.yaml +1 -1
  311. package/skills/skill-marketplace.json +1 -1
  312. package/src/cli/bootstrap-generate.ts +6 -0
  313. package/src/cli/config-inspect.ts +24 -7
  314. package/src/cli/config-trust.ts +62 -0
  315. package/src/cli/config.ts +8 -0
  316. package/src/cli/context-map.ts +75 -14
  317. package/src/cli/context.ts +46 -17
  318. package/src/cli/eval.ts +17 -3
  319. package/src/cli/modes/print.ts +32 -4
  320. package/src/cli/run.ts +16 -14
  321. package/src/cli/skills-eval.ts +10 -8
  322. package/src/cli/steer-channel.ts +31 -18
  323. package/src/cli/targets.ts +83 -31
  324. package/src/cli/tasks.ts +10 -1
  325. package/src/cli/upgrade.ts +9 -6
  326. package/src/cli/usage.ts +24 -0
  327. package/src/cli/wiki-generate.ts +239 -96
  328. package/src/core/bash-exec.ts +43 -15
  329. package/src/core/bus-events.ts +15 -0
  330. package/src/core/config.ts +33 -14
  331. package/src/core/defaults.ts +5 -4
  332. package/src/core/file-references.ts +11 -1
  333. package/src/core/incomplete-installation.ts +3 -1
  334. package/src/core/settings-layers.ts +21 -5
  335. package/src/core/termination.ts +26 -9
  336. package/src/core/untrusted-content.ts +16 -0
  337. package/src/core/workspace-trust.ts +179 -0
  338. package/src/domains/agents/builtins/coder.md +4 -2
  339. package/src/domains/agents/builtins/context-bootstrap.md +3 -1
  340. package/src/domains/agents/builtins/documenter.md +7 -4
  341. package/src/domains/agents/builtins/researcher.md +1 -0
  342. package/src/domains/agents/builtins/scout.md +7 -1
  343. package/src/domains/agents/result-contract.ts +199 -26
  344. package/src/domains/context/bootstrap-prompt.ts +11 -9
  345. package/src/domains/context/bootstrap.ts +74 -39
  346. package/src/domains/context/clio-md.ts +88 -26
  347. package/src/domains/context/codewiki/build-operation.ts +121 -0
  348. package/src/domains/context/codewiki/build-worker-protocol.ts +37 -3
  349. package/src/domains/context/codewiki/build-worker.ts +3 -35
  350. package/src/domains/context/codewiki/coordinator.ts +36 -6
  351. package/src/domains/context/codewiki/indexer.ts +59 -19
  352. package/src/domains/context/contract.ts +6 -2
  353. package/src/domains/context/extension.ts +72 -10
  354. package/src/domains/context/fingerprint.ts +39 -34
  355. package/src/domains/context/index.ts +7 -1
  356. package/src/domains/context/prompt-context.ts +55 -14
  357. package/src/domains/context/refresh.ts +9 -57
  358. package/src/domains/context/wiki/assemble.ts +14 -10
  359. package/src/domains/context/wiki/evidence.ts +209 -0
  360. package/src/domains/context/wiki/generate.ts +201 -67
  361. package/src/domains/context/wiki/meta.ts +10 -2
  362. package/src/domains/context/wiki/plan-store.ts +70 -14
  363. package/src/domains/context/wiki/plan.ts +71 -14
  364. package/src/domains/context/wiki/prompts.ts +42 -1
  365. package/src/domains/context/wiki/source-content.ts +106 -0
  366. package/src/domains/context/wiki/staleness.ts +33 -22
  367. package/src/domains/context/working-set/contract.ts +8 -2
  368. package/src/domains/context/working-set/engine.ts +17 -4
  369. package/src/domains/context/working-set/fold.ts +15 -2
  370. package/src/domains/context/working-set/marker.ts +2 -1
  371. package/src/domains/context/working-set/project.ts +18 -7
  372. package/src/domains/context/working-set/recall.ts +82 -56
  373. package/src/domains/dispatch/active-route-planner.ts +6 -3
  374. package/src/domains/dispatch/admission-queue.ts +19 -7
  375. package/src/domains/dispatch/admission.ts +3 -3
  376. package/src/domains/dispatch/budget-envelope.ts +47 -82
  377. package/src/domains/dispatch/capacity-lease.ts +57 -19
  378. package/src/domains/dispatch/contract.ts +10 -2
  379. package/src/domains/dispatch/event-pump.ts +28 -7
  380. package/src/domains/dispatch/execution-role.ts +49 -2
  381. package/src/domains/dispatch/execution-scheduler.ts +2 -0
  382. package/src/domains/dispatch/extension.ts +190 -105
  383. package/src/domains/dispatch/fleet-run.ts +20 -0
  384. package/src/domains/dispatch/gate-role-prompts.ts +4 -2
  385. package/src/domains/dispatch/parallel-writers.ts +34 -0
  386. package/src/domains/dispatch/reservation-store.ts +8 -34
  387. package/src/domains/dispatch/route-approval.ts +3 -3
  388. package/src/domains/dispatch/route-observer.ts +4 -2
  389. package/src/domains/dispatch/route-quality.ts +6 -1
  390. package/src/domains/dispatch/types.ts +4 -3
  391. package/src/domains/dispatch/worker-spawn.ts +58 -21
  392. package/src/domains/dispatch/workspace-checkpoint.ts +57 -0
  393. package/src/domains/eval/compare/behavioral.ts +81 -14
  394. package/src/domains/eval/compare/compare.ts +15 -5
  395. package/src/domains/eval/compare/envelope.ts +12 -5
  396. package/src/domains/eval/metrics/context.ts +24 -1
  397. package/src/domains/eval/metrics/tracked.ts +4 -28
  398. package/src/domains/eval/reports/comparison.ts +9 -9
  399. package/src/domains/eval/runners/clio-run.ts +5 -1
  400. package/src/domains/eval/schema/suite.ts +2 -0
  401. package/src/domains/eval/schema/validate.ts +1 -0
  402. package/src/domains/eval/suites/run.ts +189 -13
  403. package/src/domains/eval/verifiers/integrity.ts +39 -0
  404. package/src/domains/eval/verifiers/patch.ts +58 -2
  405. package/src/domains/eval/workspaces/temp-copy.ts +3 -0
  406. package/src/domains/evidence/build.ts +4 -2
  407. package/src/domains/interop/registry.ts +2 -2
  408. package/src/domains/middleware/hooks-io.ts +45 -26
  409. package/src/domains/middleware/hooks.ts +6 -0
  410. package/src/domains/middleware/injection-screen.ts +23 -0
  411. package/src/domains/middleware/rules.ts +5 -1
  412. package/src/domains/middleware/stalled-turn.ts +18 -3
  413. package/src/domains/middleware/task-board-reminder.ts +4 -2
  414. package/src/domains/middleware/task-nudge.ts +4 -1
  415. package/src/domains/mux/contract.ts +34 -1
  416. package/src/domains/mux/dock-controller.ts +8 -1
  417. package/src/domains/mux/index.ts +1 -0
  418. package/src/domains/mux/socket-client.ts +13 -3
  419. package/src/domains/observability/contract.ts +2 -2
  420. package/src/domains/observability/projection.ts +30 -9
  421. package/src/domains/prompts/compiler.ts +10 -2
  422. package/src/domains/prompts/contract.ts +7 -4
  423. package/src/domains/prompts/extension.ts +28 -64
  424. package/src/domains/prompts/fragments/identity/clio.md +23 -0
  425. package/src/domains/prompts/fragments/operating/contract.md +10 -0
  426. package/src/domains/prompts/fragments/operating/delegation.md +5 -0
  427. package/src/domains/prompts/fragments/wiki/page.md +28 -15
  428. package/src/domains/prompts/fragments/wiki/plan.md +4 -4
  429. package/src/domains/prompts/preload-prefix.ts +31 -0
  430. package/src/domains/prompts/preload.ts +135 -61
  431. package/src/domains/providers/auth/backend-file.ts +15 -11
  432. package/src/domains/providers/auth/storage.ts +3 -5
  433. package/src/domains/providers/catalog.ts +18 -3
  434. package/src/domains/providers/runtime-resolution.ts +11 -9
  435. package/src/domains/providers/runtimes/cloud/openrouter.ts +2 -0
  436. package/src/domains/resources/skills/promotion.ts +8 -1
  437. package/src/domains/safety/action-classifier.ts +9 -0
  438. package/src/domains/safety/autonomy.ts +10 -1
  439. package/src/domains/safety/contract.ts +5 -1
  440. package/src/domains/safety/default-path-policy.ts +11 -0
  441. package/src/domains/safety/extension.ts +11 -2
  442. package/src/domains/safety/policy-engine.ts +189 -32
  443. package/src/domains/safety/project-policy.ts +7 -2
  444. package/src/domains/safety/workspace-trust.ts +43 -0
  445. package/src/domains/session/compaction/compact.ts +384 -21
  446. package/src/domains/session/compaction/cut-point.ts +42 -5
  447. package/src/domains/session/compaction/tokens.ts +9 -1
  448. package/src/domains/session/decision-board.ts +43 -33
  449. package/src/domains/session/entries.ts +169 -4
  450. package/src/domains/session/prompt-manifest.ts +47 -8
  451. package/src/domains/session/task-board.ts +21 -3
  452. package/src/domains/user-tasks/handoff.ts +16 -0
  453. package/src/engine/acp/adapter.ts +44 -12
  454. package/src/engine/acp/server.ts +1 -0
  455. package/src/engine/acp/transport.ts +2 -1
  456. package/src/engine/acp/types.ts +6 -1
  457. package/src/engine/antigravity/subprocess-runtime.ts +20 -4
  458. package/src/engine/api-registry.ts +19 -2
  459. package/src/engine/apis/openai-completions.ts +13 -6
  460. package/src/engine/apis/output-budget.ts +26 -10
  461. package/src/engine/claude/sdk-runtime.ts +4 -3
  462. package/src/engine/env-api-keys.ts +2 -1
  463. package/src/engine/external-subprocess.ts +14 -3
  464. package/src/engine/loop-guard.ts +19 -2
  465. package/src/engine/provider-diagnostics.ts +129 -0
  466. package/src/engine/provider-payload.ts +3 -1
  467. package/src/engine/worker-runtime.ts +13 -2
  468. package/src/engine/worker-tools.ts +5 -1
  469. package/src/entry/extension-reload.ts +1 -0
  470. package/src/entry/orchestrator.ts +53 -15
  471. package/src/interactive/chat-loop-messages.ts +12 -4
  472. package/src/interactive/chat-loop.ts +115 -45
  473. package/src/interactive/chat-renderer.ts +60 -0
  474. package/src/interactive/context-recall-command.ts +2 -1
  475. package/src/interactive/dispatch-board.ts +17 -2
  476. package/src/interactive/editor-submit.ts +13 -0
  477. package/src/interactive/interactive-application.ts +8 -2
  478. package/src/interactive/interactive-event-projection.ts +7 -1
  479. package/src/interactive/interactive-presentation.ts +15 -7
  480. package/src/interactive/interactive-slash-runtime.ts +2 -0
  481. package/src/interactive/layout.ts +2 -1
  482. package/src/interactive/model-session-replay.ts +2 -2
  483. package/src/interactive/overlay-frame.ts +1 -0
  484. package/src/interactive/overlay-general-openers.ts +3 -1
  485. package/src/interactive/overlay-session-lifecycle.ts +6 -0
  486. package/src/interactive/overlays/ask-user.ts +1 -0
  487. package/src/interactive/overlays/message-picker.ts +1 -1
  488. package/src/interactive/renderers/tool-execution.ts +17 -1
  489. package/src/interactive/renderers/worker-entry.ts +25 -10
  490. package/src/interactive/slash-commands.ts +9 -7
  491. package/src/interactive/turn-context.ts +221 -53
  492. package/src/interactive/turn-middleware.ts +3 -1
  493. package/src/interactive/turn-persistence.ts +3 -0
  494. package/src/interactive/turn-runtime.ts +11 -2
  495. package/src/interactive/turn-state.ts +10 -9
  496. package/src/interactive/watch-pane.ts +18 -4
  497. package/src/interactive/worker-stream.ts +7 -7
  498. package/src/tools/agent-tools.ts +6 -3
  499. package/src/tools/bash.ts +1 -1
  500. package/src/tools/builtin-tool-catalog.ts +9 -2
  501. package/src/tools/codewiki/code-nav.ts +4 -10
  502. package/src/tools/compete-judge-task.ts +71 -0
  503. package/src/tools/compete-worktrees.ts +34 -0
  504. package/src/tools/context/index.ts +32 -7
  505. package/src/tools/context/surface.ts +15 -4
  506. package/src/tools/decide.ts +1 -1
  507. package/src/tools/dispatch-admission.ts +12 -1
  508. package/src/tools/dispatch-arguments.ts +38 -1
  509. package/src/tools/dispatch-plan.ts +7 -7
  510. package/src/tools/dispatch-runner.ts +48 -32
  511. package/src/tools/dispatch-schema.ts +30 -23
  512. package/src/tools/dispatch-scout-admission.ts +10 -44
  513. package/src/tools/dispatch-scout.ts +2 -3
  514. package/src/tools/find.ts +13 -4
  515. package/src/tools/grep.ts +13 -1
  516. package/src/tools/ls.ts +7 -1
  517. package/src/tools/monitor.ts +26 -11
  518. package/src/tools/network-policy.ts +11 -24
  519. package/src/tools/observation.ts +39 -2
  520. package/src/tools/read.ts +112 -15
  521. package/src/tools/registry.ts +54 -17
  522. package/src/tools/result-shaping.ts +110 -2
  523. package/src/tools/tasks.ts +33 -7
  524. package/src/tools/verify/frontend.ts +67 -30
  525. package/src/tools/verify/numeric.ts +6 -1
  526. package/src/tools/web-fetch-network.ts +179 -0
  527. package/src/tools/web-fetch-surface.ts +2 -1
  528. package/src/tools/web-fetch.ts +15 -13
  529. package/src/tools/worker-evidence.ts +27 -0
  530. package/src/worker/spec-contract.ts +12 -8
  531. package/dist/builtins-WGALA46I.js +0 -22
  532. package/dist/chunk-2WZ546HR.js +0 -792
  533. package/dist/chunk-5PSMVOLM.js +0 -56
  534. package/dist/chunk-EL24TAU4.js +0 -1560
  535. package/dist/chunk-IZXGRF7P.js +0 -4048
  536. package/dist/chunk-JVCV3ICN.js +0 -47
  537. package/dist/chunk-MNJGS2IN.js +0 -33
  538. package/dist/chunk-O5CVSAG5.js +0 -122
  539. package/dist/chunk-ODGTEFFI.js +0 -50
  540. package/dist/chunk-OQE5J4C6.js +0 -73
  541. package/dist/chunk-UUVG37B4.js +0 -244
  542. package/dist/chunk-V6HJFQZE.js +0 -228
  543. package/dist/clio-QLICPCF5.js +0 -25
  544. package/dist/configure-VEPX4NMX.js +0 -55
  545. package/dist/context-clear-S4ZJCQUX.js +0 -182
  546. package/dist/detail-A7JAVSIG.js +0 -98
  547. package/dist/evidence-4F5USFKH.js +0 -208
  548. package/dist/fleet-view-MN2VG4MR.js +0 -101
  549. package/dist/inventory-C26CFDRR.js +0 -101
  550. package/dist/preload-P6DGH2PZ.js +0 -13
  551. package/dist/slash-commands-ZXPJD64J.js +0 -92
  552. package/dist/tasks-IPAGMEIX.js +0 -36
  553. package/dist/tools-EFFEAIDP.js +0 -28
  554. package/dist/verify-FWYGPKMR.js +0 -29
  555. package/dist/wiki-generate-743CIGJW.js +0 -476
@@ -1,4048 +0,0 @@
1
- import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
- import {
3
- planWikiGeneration
4
- } from "./chunk-R6Q67RJH.js";
5
- import {
6
- loadFragments,
7
- renderCodewikiDigest
8
- } from "./chunk-V6HJFQZE.js";
9
- import {
10
- loadMemoryRecordsSync
11
- } from "./chunk-EL24TAU4.js";
12
- import {
13
- WIKI_INDEX,
14
- WIKI_PLAN_FILE,
15
- WIKI_QUICKSTART,
16
- changedPathsSince,
17
- computeWikiContentHash,
18
- computeWikiContentHashOfDir,
19
- currentWikiGitHead,
20
- isGeneratedWikiFile,
21
- listWikiPages,
22
- listWikiPagesInDir,
23
- readWikiMeta,
24
- readWikiPage,
25
- readWikiPlanFile,
26
- renderWikiPage,
27
- resolveSourcePath,
28
- scopePlanForUpdate,
29
- unclaimedCandidates,
30
- wikiCompleteness,
31
- wikiDir,
32
- wikiMarkdownFilesInDir,
33
- wikiMetaPath,
34
- wikiStaleness,
35
- writeWikiMeta,
36
- writeWikiPlanFile
37
- } from "./chunk-ELZVTCGV.js";
38
- import {
39
- buildCodewikiCandidate,
40
- coordinateCodewikiExclusive,
41
- coordinateCodewikiWrite,
42
- drainCodewikiWrites,
43
- readClioState,
44
- statePath,
45
- writeClioState
46
- } from "./chunk-MXHC5QYU.js";
47
- import {
48
- readSessionEntriesForId
49
- } from "./chunk-6UINWWS6.js";
50
- import {
51
- filterEntriesToActivePath
52
- } from "./chunk-W6GROXXM.js";
53
- import {
54
- foldDecisionBoard
55
- } from "./chunk-I2DWJ4GM.js";
56
- import {
57
- createTomlFileReader,
58
- tomlTableAt
59
- } from "./chunk-LCGCVYZ4.js";
60
- import {
61
- describeValidationContract,
62
- loadValidationContract
63
- } from "./chunk-V76WTFTW.js";
64
- import {
65
- classifyProjectPreload
66
- } from "./chunk-JVCV3ICN.js";
67
- import {
68
- compileGlobRegex,
69
- normalizeGlobInput
70
- } from "./chunk-VG7TBQIY.js";
71
- import {
72
- decisionRef
73
- } from "./chunk-54X7T7DK.js";
74
- import {
75
- ceilChars
76
- } from "./chunk-NZMNUPZZ.js";
77
- import {
78
- INTEROP_AGENT_KINDS
79
- } from "./chunk-KXDSS5WJ.js";
80
- import {
81
- BusChannels
82
- } from "./chunk-F4EKGO4N.js";
83
- import {
84
- computeFingerprintCached,
85
- isStale
86
- } from "./chunk-UUVG37B4.js";
87
- import {
88
- codewikiPath,
89
- readCodewiki
90
- } from "./chunk-LBMZMYH2.js";
91
- import {
92
- detectProjectType
93
- } from "./chunk-XAKHZX5N.js";
94
- import {
95
- enumerateWorkspaceFiles
96
- } from "./chunk-33YXPOE3.js";
97
- import {
98
- require_dist
99
- } from "./chunk-APJ265NV.js";
100
- import {
101
- clioDataDir,
102
- clioStateDir,
103
- resolveClioDirs
104
- } from "./chunk-BYP5D4HI.js";
105
- import {
106
- __toESM,
107
- init_esm_shims
108
- } from "./chunk-3R73A4XB.js";
109
-
110
- // src/domains/context/index.ts
111
- init_esm_shims();
112
-
113
- // src/domains/context/adoption.ts
114
- init_esm_shims();
115
- import { createHash } from "node:crypto";
116
- import { existsSync, lstatSync, readdirSync, readFileSync, statSync } from "node:fs";
117
- import { homedir } from "node:os";
118
- import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
119
- var MAX_SOURCE_BYTES = 128 * 1024;
120
- var MAX_TOTAL_SOURCE_BYTES = 1024 * 1024;
121
- var MAX_RECURSIVE_FILES = 80;
122
- var MAX_RULES_PER_SOURCE = 4;
123
- var MAX_IMPORTED_RULES = 20;
124
- var PROVIDER_LABELS = {
125
- "claude-code": "Claude Code",
126
- agents: "Agent Skills",
127
- codex: "Codex",
128
- gemini: "Gemini",
129
- cursor: "Cursor",
130
- copilot: "GitHub Copilot",
131
- opencode: "OpenCode"
132
- };
133
- var KIND_LABELS = {
134
- instructions: "instructions",
135
- settings: "settings",
136
- command: "command",
137
- agent: "agent",
138
- skill: "skill",
139
- rule: "rule"
140
- };
141
- var GENERATED_OR_SECRET_DIRS = /* @__PURE__ */ new Set([
142
- ".git",
143
- ".clio-coder",
144
- ".antigravitycli",
145
- "node_modules",
146
- "dist",
147
- "build",
148
- "target",
149
- ".venv",
150
- "venv",
151
- "cache",
152
- "caches",
153
- "history",
154
- "histories",
155
- "sessions",
156
- "logs",
157
- "tmp",
158
- "temp",
159
- "state",
160
- "projects"
161
- ]);
162
- var NESTED_INSTRUCTION_PROVIDERS = new Map(
163
- INTEROP_AGENT_KINDS.flatMap((kind) => {
164
- const provider = kind.adoptionProvider;
165
- if (provider === void 0) return [];
166
- return kind.instructionFiles.filter((file) => !file.includes("/")).map((file) => [file, provider]);
167
- })
168
- );
169
- var UNSAFE_FILE_NAME_RE = /(^\.env(?:\.|$)|secret|credential|token|password|history|cache|session|\.log$|state\.json$)/i;
170
- var RULE_KEYWORDS = /\b(always|never|must|should|prefer|avoid|do not|don't|use|run|keep|write|allow|allows|deny|denies|enable|enables|define|defines)\b/i;
171
- var SECRET_LINE_PATTERNS = [
172
- /-----BEGIN [A-Z ]*PRIVATE KEY-----/i,
173
- /\bauthorization\s*[:=]\s*bearer\s+\S+/i,
174
- /\b(?:api[_-]?key|auth[_-]?token|access[_-]?token|refresh[_-]?token|password|secret|credential)\b\s*[:=]\s*["']?[^\s"'`,;]{8,}/i,
175
- /\b(?:ghp|gho|ghu|ghs|github_pat)_[A-Za-z0-9_]{20,}\b/,
176
- /\bsk-[A-Za-z0-9_-]{20,}\b/,
177
- /\bxox[baprs]-[A-Za-z0-9-]{20,}\b/,
178
- /\bAIza[0-9A-Za-z_-]{20,}\b/
179
- ];
180
- function sha256(text) {
181
- return createHash("sha256").update(text).digest("hex");
182
- }
183
- function normalizeText(text) {
184
- return text.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n");
185
- }
186
- function isRecord(value) {
187
- return typeof value === "object" && value !== null && !Array.isArray(value);
188
- }
189
- function isSubpath(parent, child) {
190
- const rel = relative(parent, child);
191
- return rel === "" || !rel.startsWith("..") && !rel.includes(`..${sep}`);
192
- }
193
- function displayPath(filePath, cwd, home) {
194
- const abs = resolve(filePath);
195
- const cwdAbs = resolve(cwd);
196
- const homeAbs = resolve(home);
197
- if (isSubpath(cwdAbs, abs)) {
198
- const rel = relative(cwdAbs, abs).split(sep).join("/");
199
- return rel.length > 0 ? rel : basename(abs);
200
- }
201
- if (isSubpath(homeAbs, abs)) {
202
- const rel = relative(homeAbs, abs).split(sep).join("/");
203
- return rel.length > 0 ? `~/${rel}` : "~";
204
- }
205
- return abs;
206
- }
207
- function unsafePathName(filePath) {
208
- const name2 = basename(filePath);
209
- return UNSAFE_FILE_NAME_RE.test(name2);
210
- }
211
- function safeDirEntryName(name2) {
212
- const lower = name2.toLowerCase();
213
- if (GENERATED_OR_SECRET_DIRS.has(lower)) return false;
214
- if (lower.includes("secret") || lower.includes("credential") || lower.includes("token")) return false;
215
- return true;
216
- }
217
- function hasSecretLikeLine(text) {
218
- for (const line of text.split("\n")) {
219
- if (SECRET_LINE_PATTERNS.some((pattern) => pattern.test(line))) return true;
220
- }
221
- return false;
222
- }
223
- function collectFiles(dir, maxDepth, accept, out3 = [], depth = 0) {
224
- if (out3.length >= MAX_RECURSIVE_FILES) return out3;
225
- let entries;
226
- try {
227
- entries = readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
228
- } catch {
229
- return out3;
230
- }
231
- for (const entry of entries) {
232
- if (out3.length >= MAX_RECURSIVE_FILES) break;
233
- if (entry.isSymbolicLink()) continue;
234
- const filePath = join(dir, entry.name);
235
- if (entry.isDirectory()) {
236
- if (depth >= maxDepth || !safeDirEntryName(entry.name)) continue;
237
- collectFiles(filePath, maxDepth, accept, out3, depth + 1);
238
- continue;
239
- }
240
- if (!entry.isFile()) continue;
241
- if (unsafePathName(filePath)) continue;
242
- if (accept(filePath)) out3.push(filePath);
243
- }
244
- return out3;
245
- }
246
- function markdownLike(filePath) {
247
- const ext = extname(filePath).toLowerCase();
248
- return ext === ".md" || ext === ".mdc";
249
- }
250
- function jsonLike(filePath) {
251
- return extname(filePath).toLowerCase() === ".json";
252
- }
253
- function discoverCandidateSpecs(cwd, home, includeGlobal) {
254
- const specs = [];
255
- const seen = /* @__PURE__ */ new Set();
256
- let order = 0;
257
- const add = (path, scope, provider, kind) => {
258
- const abs = resolve(path);
259
- if (seen.has(abs)) return;
260
- seen.add(abs);
261
- const scopedDir = scope === "project" && kind === "instructions" ? relative(cwd, dirname(abs)) : "";
262
- specs.push({
263
- path: abs,
264
- scope,
265
- provider,
266
- kind,
267
- ...scope === "project" && kind === "instructions" ? { directoryScope: scopedDir.length === 0 ? "." : scopedDir.split(sep).join("/") } : {},
268
- order
269
- });
270
- order += 1;
271
- };
272
- const addProject = (relPath, provider, kind) => {
273
- add(join(cwd, relPath), "project", provider, kind);
274
- };
275
- const addProjectDir = (relPath, provider, kind, maxDepth, accept) => {
276
- for (const filePath of collectFiles(join(cwd, relPath), maxDepth, accept)) add(filePath, "project", provider, kind);
277
- };
278
- for (const kind of INTEROP_AGENT_KINDS) {
279
- if (kind.adoptionProvider === void 0) continue;
280
- for (const file of kind.instructionFiles) addProject(file, kind.adoptionProvider, "instructions");
281
- }
282
- const visibleWorkspaceFiles = enumerateWorkspaceFiles(cwd);
283
- for (const relPath of visibleWorkspaceFiles) {
284
- const parts = relPath.split("/");
285
- if (parts.length - 1 > 6) continue;
286
- const name2 = parts.at(-1);
287
- const provider = name2 === void 0 ? void 0 : NESTED_INSTRUCTION_PROVIDERS.get(name2);
288
- if (provider === void 0) continue;
289
- add(join(cwd, relPath), "project", provider, "instructions");
290
- }
291
- addProject(join(".claude", "settings.json"), "claude-code", "settings");
292
- addProjectDir(join(".claude", "commands"), "claude-code", "command", 3, markdownLike);
293
- addProjectDir(join(".claude", "agents"), "claude-code", "agent", 2, markdownLike);
294
- for (const kind of INTEROP_AGENT_KINDS) {
295
- if (kind.adoptionProvider === void 0 || kind.projectSkillRoot === void 0) continue;
296
- addProjectDir(kind.projectSkillRoot, kind.adoptionProvider, "skill", 4, markdownLike);
297
- }
298
- addProject(join(".gemini", "settings.json"), "gemini", "settings");
299
- addProject(join(".gemini", "config.json"), "gemini", "settings");
300
- addProjectDir(
301
- join(".gemini", "rules"),
302
- "gemini",
303
- "rule",
304
- 2,
305
- (filePath) => markdownLike(filePath) || jsonLike(filePath)
306
- );
307
- addProjectDir(
308
- join(".gemini", "config"),
309
- "gemini",
310
- "rule",
311
- 2,
312
- (filePath) => markdownLike(filePath) || jsonLike(filePath)
313
- );
314
- addProjectDir(join(".cursor", "rules"), "cursor", "rule", 0, markdownLike);
315
- if (includeGlobal) add(join(home, ".codex", "AGENTS.md"), "global", "codex", "instructions");
316
- return specs.filter((spec) => existsSync(spec.path));
317
- }
318
- function stripFrontmatter(text) {
319
- if (!text.startsWith("---\n")) return text;
320
- const end = text.indexOf("\n---", 4);
321
- if (end === -1) return text;
322
- return text.slice(end + "\n---".length).replace(/^\n+/, "");
323
- }
324
- function stripCodeFences(text) {
325
- const lines = [];
326
- let inFence = false;
327
- for (const line of text.split("\n")) {
328
- if (/^\s*```/.test(line)) {
329
- inFence = !inFence;
330
- continue;
331
- }
332
- if (!inFence) lines.push(line);
333
- }
334
- return lines.join("\n");
335
- }
336
- function isBarePathOrFileName(text) {
337
- const token = /^`([^`]+)`$/.exec(text)?.[1] ?? text;
338
- if (/\s/.test(token)) return false;
339
- if (!/^[A-Za-z0-9_@.+~/-]+$/.test(token)) return false;
340
- return token.includes("/") || extname(token).length > 1;
341
- }
342
- function cleanRuleText(raw) {
343
- let text = raw.replace(/<!--.*?-->/g, "").replace(/^\[[ xX]\]\s+/, "").replace(/\s+/g, " ").trim();
344
- text = text.replace(/^[#>\s]+/, "").trim();
345
- if (text.length < 8 || text.length > 260) return null;
346
- if (/^(todo|note|example|marker)\b/i.test(text)) return null;
347
- if (/\$[A-Z][A-Z0-9_]*|\{\{[^}]+\}\}|<\/?[A-Z][A-Z0-9_-]*>/i.test(text)) return null;
348
- if (isBarePathOrFileName(text)) return null;
349
- if (!RULE_KEYWORDS.test(text)) return null;
350
- if (hasSecretLikeLine(text)) return null;
351
- if (text.length > 200) text = `${text.slice(0, 197).trimEnd()}\u2026`;
352
- return text;
353
- }
354
- function extractMarkdownRules(content) {
355
- const text = stripCodeFences(stripFrontmatter(content));
356
- const rules = [];
357
- const seen = /* @__PURE__ */ new Set();
358
- for (const line of text.split("\n")) {
359
- const trimmed = line.trim();
360
- if (trimmed.length === 0 || trimmed.startsWith("|") || /^#{1,6}\s/.test(trimmed)) continue;
361
- const bullet = /^(?:[-*+]\s+|\d+\.\s+)(.+?)\s*$/.exec(trimmed)?.[1] ?? null;
362
- const candidate = bullet ?? (/^[A-Z][^.!?]{8,220}[.!?]?$/.test(trimmed) ? trimmed : null);
363
- if (!candidate) continue;
364
- const cleaned = cleanRuleText(candidate);
365
- if (!cleaned) continue;
366
- const key = normalizeRuleKey(cleaned);
367
- if (seen.has(key)) continue;
368
- seen.add(key);
369
- rules.push(cleaned);
370
- if (rules.length >= MAX_RULES_PER_SOURCE) break;
371
- }
372
- return rules;
373
- }
374
- function stringArray(value) {
375
- if (!Array.isArray(value)) return [];
376
- return value.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim());
377
- }
378
- function stringField(record, key) {
379
- const value = record[key];
380
- return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
381
- }
382
- function formatShortList(items, limit = 4) {
383
- const cleaned = items.map((item) => item.replace(/\s+/g, " ").trim()).filter(Boolean);
384
- const shown = cleaned.slice(0, limit).map((item) => `\`${item.length > 48 ? `${item.slice(0, 45)}\u2026` : item}\``);
385
- if (cleaned.length > limit) shown.push(`+${cleaned.length - limit} more`);
386
- return shown.join(", ");
387
- }
388
- function extractSettingsRules(provider, content) {
389
- let parsed;
390
- try {
391
- parsed = JSON.parse(content);
392
- } catch {
393
- return [];
394
- }
395
- if (!isRecord(parsed)) return [];
396
- const rules = [];
397
- if (provider === "claude-code") {
398
- const permissions = parsed.permissions;
399
- if (isRecord(permissions)) {
400
- const allow = stringArray(permissions.allow);
401
- const deny = stringArray(permissions.deny);
402
- const claudePermissionSetting = stringField(permissions, "defaultMode");
403
- if (allow.length > 0) rules.push(`Claude Code allows tools: ${formatShortList(allow)}.`);
404
- if (deny.length > 0) rules.push(`Claude Code denies tools: ${formatShortList(deny)}.`);
405
- if (claudePermissionSetting)
406
- rules.push(`Claude Code declares permission setting \`${claudePermissionSetting}\` for this project.`);
407
- }
408
- if (parsed.enableAllProjectMcpServers === true) rules.push("Claude Code enables all project MCP servers.");
409
- }
410
- if (provider === "gemini") {
411
- const contextFileName = stringField(parsed, "contextFileName");
412
- if (contextFileName) rules.push(`Gemini uses \`${contextFileName}\` as an additional context file.`);
413
- const mcpServers = parsed.mcpServers;
414
- if (isRecord(mcpServers) && Object.keys(mcpServers).length > 0) {
415
- rules.push(`Gemini project settings define MCP servers: ${formatShortList(Object.keys(mcpServers))}.`);
416
- }
417
- }
418
- return rules.map((rule) => cleanRuleText(rule)).filter((rule) => Boolean(rule));
419
- }
420
- function extractRules(spec, content) {
421
- if (spec.kind === "settings" || jsonLike(spec.path)) return extractSettingsRules(spec.provider, content);
422
- return extractMarkdownRules(content);
423
- }
424
- function normalizeRuleKey(text) {
425
- return text.toLowerCase().replace(/`([^`]+)`/g, "$1").replace(/[^a-z0-9.+:#/-]+/g, " ").replace(/\s+/g, " ").trim().replace(/[.!?]+$/, "");
426
- }
427
- function classifyConflict(text) {
428
- const normalized = text.toLowerCase().replace(/`/g, "");
429
- const packageManager2 = /\b(?:always\s+|must\s+|should\s+|prefer\s+|use\s+|run\s+)*(?:use|prefer|run)\s+(pnpm|npm|yarn|bun)\b/.exec(
430
- normalized
431
- );
432
- if (packageManager2?.[1]) return { key: "package-manager", value: packageManager2[1] };
433
- const testRunner = /\b(?:always\s+|must\s+|should\s+|prefer\s+|use\s+|run\s+)*(?:use|prefer|run)\s+(node:test|vitest|jest|pytest|cargo test|go test)\b/.exec(
434
- normalized
435
- );
436
- if (testRunner?.[1]) return { key: "test-runner", value: testRunner[1] };
437
- return void 0;
438
- }
439
- function sourcePriority(source) {
440
- const kindPriority = {
441
- instructions: 0,
442
- rule: 1e3,
443
- settings: 2e3,
444
- command: 3e3,
445
- agent: 4e3,
446
- skill: 5e3
447
- };
448
- const scopeDepth = source.directoryScope ? source.directoryScope.split("/").filter((part) => part !== ".").length : 0;
449
- return (source.scope === "project" ? 0 : 1e4) + kindPriority[source.kind] + scopeDepth * 10 + source.order;
450
- }
451
- function buildImportPlan(sources) {
452
- const candidates = [];
453
- for (const source of sources) {
454
- const rules = extractRules(
455
- { path: source.path, scope: source.scope, provider: source.provider, kind: source.kind, order: 0 },
456
- source.content
457
- );
458
- rules.forEach((text, index) => {
459
- const conflict = classifyConflict(text);
460
- candidates.push({ text, source, index, ...conflict ? { conflict } : {} });
461
- });
462
- }
463
- candidates.sort((a, b) => {
464
- const sourceDelta = sourcePriority(a.source) - sourcePriority(b.source);
465
- return sourceDelta !== 0 ? sourceDelta : a.index - b.index;
466
- });
467
- const accepted = [];
468
- const byNormalizedText = /* @__PURE__ */ new Map();
469
- const byConflictKey = /* @__PURE__ */ new Map();
470
- const conflicts = /* @__PURE__ */ new Map();
471
- for (const candidate of candidates) {
472
- const normalized = normalizeRuleKey(candidate.text);
473
- const existing = byNormalizedText.get(normalized);
474
- if (existing) {
475
- if (!existing.sources.includes(candidate.source.displayPath)) existing.sources.push(candidate.source.displayPath);
476
- if (!existing.providers.includes(candidate.source.providerLabel))
477
- existing.providers.push(candidate.source.providerLabel);
478
- if (candidate.source.directoryScope) {
479
- existing.directoryScopes ??= [];
480
- if (!existing.directoryScopes.includes(candidate.source.directoryScope)) {
481
- existing.directoryScopes.push(candidate.source.directoryScope);
482
- }
483
- }
484
- continue;
485
- }
486
- if (candidate.conflict) {
487
- const prior = byConflictKey.get(candidate.conflict.key);
488
- if (prior && prior.value !== candidate.conflict.value) {
489
- let conflict = conflicts.get(candidate.conflict.key);
490
- if (!conflict) {
491
- conflict = {
492
- key: candidate.conflict.key,
493
- kept: prior.rule.text,
494
- keptSources: [...prior.rule.sources],
495
- skipped: []
496
- };
497
- conflicts.set(candidate.conflict.key, conflict);
498
- }
499
- conflict.skipped.push({
500
- text: candidate.text,
501
- source: candidate.source.displayPath,
502
- provider: candidate.source.providerLabel
503
- });
504
- continue;
505
- }
506
- }
507
- const rule = {
508
- text: candidate.text,
509
- sources: [candidate.source.displayPath],
510
- providers: [candidate.source.providerLabel],
511
- ...candidate.source.directoryScope ? { directoryScopes: [candidate.source.directoryScope] } : {},
512
- ...candidate.conflict ? { conflictKey: candidate.conflict.key } : {}
513
- };
514
- accepted.push(rule);
515
- byNormalizedText.set(normalized, rule);
516
- if (candidate.conflict) byConflictKey.set(candidate.conflict.key, { value: candidate.conflict.value, rule });
517
- if (accepted.length >= MAX_IMPORTED_RULES) break;
518
- }
519
- return { importedRules: accepted, conflicts: [...conflicts.values()] };
520
- }
521
- function rejectedCandidate(spec, displayPath2, reason, evidence) {
522
- return {
523
- path: spec.path,
524
- displayPath: displayPath2,
525
- scope: spec.scope,
526
- provider: spec.provider,
527
- kind: spec.kind,
528
- ...spec.directoryScope ? { directoryScope: spec.directoryScope } : {},
529
- reason,
530
- fingerprintSha256: sha256(`rejected\0${reason}\0${evidence}`)
531
- };
532
- }
533
- function statEvidence(stat) {
534
- return `${stat.size}:${Math.floor(stat.mtimeMs)}:${stat.mode}`;
535
- }
536
- function readCandidate(spec, cwd, home) {
537
- const shown = displayPath(spec.path, cwd, home);
538
- if (unsafePathName(spec.path)) {
539
- return rejectedCandidate(spec, shown, "unsafe path name", "");
540
- }
541
- let stat;
542
- try {
543
- const lst = lstatSync(spec.path);
544
- if (lst.isSymbolicLink()) {
545
- return rejectedCandidate(spec, shown, "symlink skipped", statEvidence(lst));
546
- }
547
- stat = statSync(spec.path);
548
- } catch {
549
- return null;
550
- }
551
- if (!stat.isFile()) return null;
552
- if (stat.size > MAX_SOURCE_BYTES) {
553
- return rejectedCandidate(spec, shown, "file too large", statEvidence(stat));
554
- }
555
- let raw;
556
- try {
557
- raw = readFileSync(spec.path, "utf8");
558
- } catch {
559
- return rejectedCandidate(spec, shown, "unreadable", statEvidence(stat));
560
- }
561
- if (raw.includes("\0")) {
562
- return rejectedCandidate(spec, shown, "binary content", raw);
563
- }
564
- const content = normalizeText(raw);
565
- if (hasSecretLikeLine(content)) {
566
- return rejectedCandidate(spec, shown, "secret-like content", content);
567
- }
568
- const rules = extractRules(spec, content);
569
- return {
570
- path: spec.path,
571
- displayPath: shown,
572
- scope: spec.scope,
573
- provider: spec.provider,
574
- providerLabel: PROVIDER_LABELS[spec.provider],
575
- kind: spec.kind,
576
- kindLabel: KIND_LABELS[spec.kind],
577
- ...spec.directoryScope ? { directoryScope: spec.directoryScope } : {},
578
- content,
579
- contentSha256: sha256(content),
580
- byteLength: Buffer.byteLength(content, "utf8"),
581
- itemCount: rules.length,
582
- order: spec.order
583
- };
584
- }
585
- function sourceSnapshot(source) {
586
- if ("content" in source) {
587
- return {
588
- path: source.path,
589
- scope: source.scope,
590
- provider: source.provider,
591
- kind: source.kind,
592
- ...source.directoryScope ? { directoryScope: source.directoryScope } : {},
593
- sha256: source.contentSha256
594
- };
595
- }
596
- return {
597
- path: source.path,
598
- scope: source.scope,
599
- provider: source.provider,
600
- kind: source.kind,
601
- ...source.directoryScope ? { directoryScope: source.directoryScope } : {},
602
- sha256: source.fingerprintSha256,
603
- status: "rejected",
604
- reason: source.reason
605
- };
606
- }
607
- function sourceSetHash(snapshots) {
608
- const hash = createHash("sha256");
609
- for (const snapshot of snapshots) {
610
- hash.update(
611
- `${snapshot.scope}\0${snapshot.provider}\0${snapshot.kind}\0${snapshot.path}\0${snapshot.directoryScope ?? ""}\0${snapshot.status ?? "accepted"}\0${snapshot.reason ?? ""}\0${snapshot.sha256}
612
- `
613
- );
614
- }
615
- return hash.digest("hex");
616
- }
617
- function adoptionSnapshotsHash(snapshots) {
618
- return sourceSetHash([...snapshots].sort((a, b) => a.path.localeCompare(b.path)));
619
- }
620
- function scanAgentConfigs(options) {
621
- const cwd = resolve(options.cwd);
622
- const home = resolve(options.homeDir ?? homedir());
623
- const includeGlobal = options.includeGlobal === true;
624
- const sources = [];
625
- const rejected = [];
626
- let acceptedSourceBytes = 0;
627
- for (const spec of discoverCandidateSpecs(cwd, home, includeGlobal)) {
628
- const result = readCandidate(spec, cwd, home);
629
- if (!result) continue;
630
- if (!("content" in result)) {
631
- rejected.push(result);
632
- continue;
633
- }
634
- if (acceptedSourceBytes + result.byteLength > MAX_TOTAL_SOURCE_BYTES) {
635
- rejected.push({
636
- path: result.path,
637
- displayPath: result.displayPath,
638
- scope: result.scope,
639
- provider: result.provider,
640
- kind: result.kind,
641
- ...result.directoryScope ? { directoryScope: result.directoryScope } : {},
642
- reason: "aggregate source byte budget exceeded",
643
- fingerprintSha256: sha256(`rejected\0aggregate source byte budget exceeded\0${result.contentSha256}`)
644
- });
645
- continue;
646
- }
647
- acceptedSourceBytes += result.byteLength;
648
- sources.push(result);
649
- }
650
- sources.sort((a, b) => {
651
- const scopeDelta = (a.scope === "project" ? 0 : 1) - (b.scope === "project" ? 0 : 1);
652
- return scopeDelta !== 0 ? scopeDelta : a.order - b.order;
653
- });
654
- const plan = buildImportPlan(sources);
655
- const sourceSnapshots = [...sources.map(sourceSnapshot), ...rejected.map(sourceSnapshot)];
656
- return {
657
- cwd,
658
- homeDir: home,
659
- includeGlobal,
660
- sources,
661
- rejected,
662
- importedRules: plan.importedRules,
663
- conflicts: plan.conflicts,
664
- sourceHash: sourceSetHash(sourceSnapshots),
665
- sourceSnapshots
666
- };
667
- }
668
- function renderSourceList(paths) {
669
- if (paths.length <= 3) return paths.map((path) => `\`${path}\``).join(", ");
670
- return `${paths.slice(0, 3).map((path) => `\`${path}\``).join(", ")} +${paths.length - 3} more`;
671
- }
672
- function quoteShort(text) {
673
- const cleaned = text.replace(/\s+/g, " ").trim();
674
- return `\u201C${cleaned.length > 120 ? `${cleaned.slice(0, 117).trimEnd()}\u2026` : cleaned}\u201D`;
675
- }
676
- function renderImportedAgentContext(scan) {
677
- if (scan.sources.length === 0 && scan.rejected.length === 0) return "";
678
- const lines = [
679
- "Conflict policy: CLIO-CODER.md conventions and hard invariants are canonical; project-local imports win over explicit global imports; duplicate rules are merged by normalized text.",
680
- "",
681
- "### Adopted rules",
682
- ""
683
- ];
684
- if (scan.importedRules.length === 0) {
685
- lines.push("- No project-specific rules were adopted from external agent configs.");
686
- } else {
687
- for (const rule of scan.importedRules) {
688
- const scoped = rule.directoryScopes?.filter((scope) => scope !== ".") ?? [];
689
- lines.push(
690
- `- ${rule.text} Sources: ${renderSourceList(rule.sources)}.${scoped.length > 0 ? ` Scopes: ${renderSourceList(scoped.map((scope) => `${scope}/**`))}.` : ""}`
691
- );
692
- }
693
- }
694
- lines.push("", "### Source provenance", "");
695
- for (const source of scan.sources) {
696
- const adopted = source.itemCount === 1 ? "1 candidate" : `${source.itemCount} candidates`;
697
- const scoped = source.directoryScope && source.directoryScope !== "." ? `, scope ${source.directoryScope}/**` : "";
698
- lines.push(
699
- `- ${source.providerLabel} ${source.kindLabel} (${source.scope}${scoped}): \`${source.displayPath}\`; ${adopted}.`
700
- );
701
- }
702
- if (scan.sources.length === 0) lines.push("- No supported project-local agent config files were found.");
703
- if (scan.conflicts.length > 0) {
704
- lines.push("", "### Skipped conflicts", "");
705
- for (const conflict of scan.conflicts) {
706
- for (const skipped of conflict.skipped) {
707
- lines.push(
708
- `- ${quoteShort(skipped.text)} from \`${skipped.source}\` conflicted with ${renderSourceList(conflict.keptSources)} on ${conflict.key}; kept ${quoteShort(conflict.kept)}.`
709
- );
710
- }
711
- }
712
- }
713
- if (scan.rejected.length > 0) {
714
- lines.push("", "### Rejected sources", "");
715
- for (const rejected of scan.rejected.slice(0, 8)) {
716
- const provider = rejected.provider ? `${PROVIDER_LABELS[rejected.provider]} ` : "";
717
- lines.push(`- ${provider}\`${rejected.displayPath}\`: skipped ${rejected.reason}.`);
718
- }
719
- if (scan.rejected.length > 8) lines.push(`- ${scan.rejected.length - 8} more rejected sources omitted.`);
720
- }
721
- return lines.join("\n");
722
- }
723
- function inferAdoptionCwd(snapshots, home) {
724
- for (const snapshot of snapshots) {
725
- if (snapshot.scope !== "project") continue;
726
- let candidate = resolve(snapshot.path, "..");
727
- for (; ; ) {
728
- const match = discoverCandidateSpecs(candidate, home, false).some(
729
- (spec) => spec.path === resolve(snapshot.path) && spec.scope === snapshot.scope && spec.provider === snapshot.provider && spec.kind === snapshot.kind
730
- );
731
- if (match) return candidate;
732
- const parent = resolve(candidate, "..");
733
- if (parent === candidate) break;
734
- candidate = parent;
735
- }
736
- }
737
- return null;
738
- }
739
- function inferAdoptionHome(snapshots) {
740
- const global = snapshots.find((snapshot) => snapshot.scope === "global");
741
- return global ? resolve(global.path, "..", "..") : null;
742
- }
743
- function adoptionSourcesChanged(snapshots, options = {}) {
744
- const homeDir = resolve(options.homeDir ?? inferAdoptionHome(snapshots) ?? homedir());
745
- const cwd = options.cwd ? resolve(options.cwd) : inferAdoptionCwd(snapshots, homeDir);
746
- if (!cwd) {
747
- for (const snapshot of snapshots) {
748
- const current2 = readCandidate(
749
- {
750
- path: snapshot.path,
751
- scope: snapshot.scope,
752
- provider: snapshot.provider,
753
- kind: snapshot.kind,
754
- order: 0
755
- },
756
- resolve(snapshot.path, ".."),
757
- homeDir
758
- );
759
- if (!current2 || adoptionSnapshotsHash([sourceSnapshot(current2)]) !== adoptionSnapshotsHash([snapshot])) {
760
- return true;
761
- }
762
- }
763
- return false;
764
- }
765
- const current = scanAgentConfigs({
766
- cwd,
767
- homeDir,
768
- includeGlobal: options.includeGlobal ?? snapshots.some((snapshot) => snapshot.scope === "global")
769
- }).sourceSnapshots;
770
- return adoptionSnapshotsHash(current) !== adoptionSnapshotsHash(snapshots);
771
- }
772
-
773
- // src/domains/context/bootstrap.ts
774
- init_esm_shims();
775
- import { execFileSync } from "node:child_process";
776
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "node:fs";
777
- import { dirname as dirname3, join as join4, parse } from "node:path";
778
-
779
- // src/domains/context/clio-md.ts
780
- init_esm_shims();
781
- import { existsSync as existsSync2, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
782
- import { basename as basename2, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
783
- var FOOTER_RE = /<!--\s*clio:fingerprint v1\s*\n([\s\S]*?)\n\s*-->/;
784
- var H1_RE = /^#\s+(.+?)\s*$/gm;
785
- var H2_RE = /^##\s+(.+?)\s*$/gm;
786
- function normalizeSource(source) {
787
- return source.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n").trimStart();
788
- }
789
- function normalizeInline(value) {
790
- return value.replace(/\s+/g, " ").trim().replace(/^#{1,6}\s+/, "").trim();
791
- }
792
- function normalizeNestedMarkdown(value) {
793
- return normalizeSource(value).trim().replace(/^(#{1,2})(\s+)/gm, "###$2");
794
- }
795
- function charLen(value) {
796
- return [...value].length;
797
- }
798
- function parseFooter(source) {
799
- const warnings = [];
800
- const markerCount = (source.match(/clio:fingerprint v1/g) ?? []).length;
801
- const match = FOOTER_RE.exec(source);
802
- if (!match) {
803
- if (markerCount > 0) {
804
- return {
805
- body: source,
806
- footer: null,
807
- firstInit: false,
808
- errors: ["malformed fingerprint footer"],
809
- warnings
810
- };
811
- }
812
- return { body: source, footer: null, firstInit: true, errors: [], warnings };
813
- }
814
- const footerEnd = match.index + match[0].length;
815
- const trailing = source.slice(footerEnd).trim();
816
- if (trailing.length > 0) warnings.push("trailing content after fingerprint footer ignored");
817
- let parsed;
818
- try {
819
- parsed = JSON.parse(match[1] ?? "");
820
- } catch {
821
- return {
822
- body: source.slice(0, match.index),
823
- footer: null,
824
- firstInit: false,
825
- errors: ["fingerprint footer is not valid JSON"],
826
- warnings
827
- };
828
- }
829
- const footer = validateFooter(parsed);
830
- if (!footer) {
831
- return {
832
- body: source.slice(0, match.index),
833
- footer: null,
834
- firstInit: false,
835
- errors: ["fingerprint footer has invalid shape"],
836
- warnings
837
- };
838
- }
839
- return {
840
- body: source.slice(0, match.index),
841
- footer,
842
- firstInit: false,
843
- errors: [],
844
- warnings
845
- };
846
- }
847
- function validateFooter(value) {
848
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
849
- const obj = value;
850
- if (typeof obj.initAt !== "string" || obj.initAt.length === 0) return null;
851
- if (typeof obj.model !== "string" || obj.model.length === 0) return null;
852
- if (!(typeof obj.gitHead === "string" || obj.gitHead === null)) return null;
853
- if (typeof obj.treeHash !== "string" || !/^[0-9a-f]{64}$/.test(obj.treeHash)) return null;
854
- if (typeof obj.loc !== "number" || !Number.isInteger(obj.loc) || obj.loc < 0) return null;
855
- return {
856
- initAt: obj.initAt,
857
- model: obj.model,
858
- gitHead: obj.gitHead,
859
- treeHash: obj.treeHash,
860
- loc: obj.loc
861
- };
862
- }
863
- function readSections(body) {
864
- const headings = [...body.matchAll(H2_RE)];
865
- const sections = [];
866
- for (let i = 0; i < headings.length; i += 1) {
867
- const heading = headings[i];
868
- if (!heading || heading.index === void 0) continue;
869
- const next = headings[i + 1];
870
- const title = (heading[1] ?? "").trim();
871
- const start = heading.index + heading[0].length;
872
- const end = next?.index ?? body.length;
873
- sections.push({ title, body: body.slice(start, end).trim() });
874
- }
875
- return sections;
876
- }
877
- function sectionBody(sections, title) {
878
- return sections.find((section) => section.title.toLowerCase() === title.toLowerCase())?.body ?? "";
879
- }
880
- var RESERVED_SECTION_TITLES = /* @__PURE__ */ new Set(["conventions", "hard invariants", "imported agent context"]);
881
- function extraSections(sections) {
882
- return sections.filter((section) => !RESERVED_SECTION_TITLES.has(section.title.toLowerCase()));
883
- }
884
- function identityParagraph(afterH1) {
885
- const beforeFirstSection = afterH1.split(/^##\s+/m)[0] ?? "";
886
- const paragraphs = beforeFirstSection.trim().split(/\n\s*\n/).map((part) => part.replace(/\s+/g, " ").trim()).filter((part) => part.length > 0);
887
- return paragraphs[0] ?? "";
888
- }
889
- function parseBullets(section) {
890
- if (section.trim().length === 0) return [];
891
- return section.split("\n").map((line) => /^[-*]\s+(.+?)\s*$/.exec(line)?.[1]?.trim()).filter((line) => Boolean(line));
892
- }
893
- function parseNumbered(section) {
894
- if (section.trim().length === 0) return [];
895
- return section.split("\n").map((line) => /^\d+\.\s+(.+?)\s*$/.exec(line)?.[1]?.trim()).filter((line) => Boolean(line));
896
- }
897
- function parseClioMd(source) {
898
- const normalized = normalizeSource(source);
899
- const warnings = [];
900
- const footerResult = parseFooter(normalized);
901
- warnings.push(...footerResult.warnings);
902
- if (footerResult.errors.length > 0) return { ok: false, errors: footerResult.errors, warnings };
903
- const h1Matches = [...footerResult.body.matchAll(H1_RE)];
904
- if (h1Matches.length === 0) return { ok: false, errors: ["missing H1 heading"], warnings };
905
- if (h1Matches.length > 1) return { ok: false, errors: ["more than one H1 heading"], warnings };
906
- const h1 = h1Matches[0];
907
- if (!h1 || h1.index === void 0) return { ok: false, errors: ["missing H1 heading"], warnings };
908
- const projectName2 = (h1[1] ?? "").trim();
909
- const errors = [];
910
- if (projectName2.length === 0) errors.push("project name must not be empty");
911
- if (charLen(projectName2) > 80) warnings.push("project name is longer than the generator target");
912
- const afterH1 = footerResult.body.slice(h1.index + h1[0].length);
913
- const identity = identityParagraph(afterH1);
914
- if (identity.length === 0) errors.push("identity paragraph is required");
915
- if (charLen(identity) > 600) warnings.push("identity paragraph is longer than the generator target");
916
- const sections = readSections(afterH1);
917
- const conventions = parseBullets(sectionBody(sections, "conventions"));
918
- const invariants = parseNumbered(sectionBody(sections, "hard invariants"));
919
- const customSections = extraSections(sections);
920
- const importedAgentContext = sectionBody(sections, "imported agent context") || null;
921
- if (conventions.length > 6) warnings.push("conventions exceed the generator target of six bullets");
922
- if (invariants.length > 3) warnings.push("hard invariants exceed the generator target of three numbered rules");
923
- if (customSections.length > 8) warnings.push("custom sections exceed the generator target of eight H2 sections");
924
- for (const [index, item] of conventions.entries()) {
925
- if (charLen(item) > 200) warnings.push(`convention ${index + 1} is longer than the generator target`);
926
- }
927
- for (const [index, item] of invariants.entries()) {
928
- if (charLen(item) > 280) warnings.push(`hard invariant ${index + 1} is longer than the generator target`);
929
- }
930
- for (const [index, section] of customSections.entries()) {
931
- if (charLen(section.title) > 80)
932
- warnings.push(`custom section ${index + 1} title is longer than the generator target`);
933
- if (charLen(section.body) > 2500)
934
- warnings.push(`custom section ${index + 1} body is longer than the generator target`);
935
- }
936
- if (errors.length > 0) return { ok: false, errors, warnings };
937
- return {
938
- ok: true,
939
- value: {
940
- projectName: projectName2,
941
- identity,
942
- conventions,
943
- invariants,
944
- sections: customSections,
945
- importedAgentContext,
946
- fingerprint: footerResult.footer,
947
- firstInit: footerResult.firstInit,
948
- warnings
949
- }
950
- };
951
- }
952
- function validateForSerialization(input) {
953
- const test = parseClioMd(renderWithoutParse(input));
954
- if (!test.ok) {
955
- throw new Error(`CLIO-CODER.md serialization failed validation: ${test.errors.join("; ")}`);
956
- }
957
- }
958
- function renderWithoutParse(input) {
959
- const lines = [`# ${normalizeInline(input.projectName)}`, "", normalizeInline(input.identity)];
960
- const conventions = input.conventions.map((item) => normalizeInline(item)).filter((item) => item.length > 0);
961
- if (conventions.length > 0) {
962
- lines.push("", "## Conventions", "", ...conventions.map((item) => `- ${item}`));
963
- }
964
- const invariants = input.invariants.map((item) => normalizeInline(item)).filter((item) => item.length > 0);
965
- if (invariants.length > 0) {
966
- lines.push("", "## Hard invariants", "", ...invariants.map((item, index) => `${index + 1}. ${item}`));
967
- }
968
- for (const section of input.sections ?? []) {
969
- const title = normalizeInline(section.title);
970
- const body = normalizeNestedMarkdown(section.body);
971
- if (title.length > 0 && body.length > 0) lines.push("", `## ${title}`, "", body);
972
- }
973
- const imported = input.importedAgentContext ? normalizeNestedMarkdown(input.importedAgentContext) : void 0;
974
- if (imported && imported.length > 0) {
975
- lines.push("", "## Imported agent context", "", imported);
976
- }
977
- if (!input.fingerprint) return `${lines.join("\n")}
978
- `;
979
- const footer = JSON.stringify(input.fingerprint, null, 2);
980
- return `${lines.join("\n")}
981
-
982
- <!-- clio:fingerprint v1
983
- ${footer}
984
- -->
985
- `;
986
- }
987
- function serializeClioMd(input) {
988
- validateForSerialization(input);
989
- return renderWithoutParse(input);
990
- }
991
- function renderProjectTypeFragment(projectType) {
992
- return `<project-type>${projectType}</project-type>`;
993
- }
994
- function escapeXmlAttribute(value) {
995
- return value.replaceAll("&", "&amp;").replaceAll('"', "&quot;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
996
- }
997
- function renderProjectContextFragment(parsed, sourcePath) {
998
- const sections = [`# ${parsed.projectName}`, parsed.identity];
999
- if (parsed.conventions.length > 0) {
1000
- sections.push("## Conventions", ...parsed.conventions.map((item) => `- ${item}`));
1001
- }
1002
- if (parsed.invariants.length > 0) {
1003
- sections.push("## Hard invariants", ...parsed.invariants.map((item, index) => `${index + 1}. ${item}`));
1004
- }
1005
- for (const section of parsed.sections) {
1006
- sections.push(`## ${section.title}`, section.body);
1007
- }
1008
- if (parsed.importedAgentContext) {
1009
- sections.push("## Imported agent context", parsed.importedAgentContext);
1010
- }
1011
- const source = sourcePath ? ` path="${escapeXmlAttribute(sourcePath)}"` : "";
1012
- return `<project-context${source}>
1013
- ${sections.join("\n\n")}
1014
- </project-context>`;
1015
- }
1016
- var PROJECT_CONTEXT_CANDIDATES = ["CLIO-CODER.override.md", "CLIO-CODER.md"];
1017
- function selectedClioMdPath(directory) {
1018
- for (const filename of PROJECT_CONTEXT_CANDIDATES) {
1019
- const filePath = join2(directory, filename);
1020
- if (!existsSync2(filePath)) continue;
1021
- try {
1022
- if (statSync2(filePath).isFile()) return filePath;
1023
- } catch {
1024
- return filePath;
1025
- }
1026
- }
1027
- return null;
1028
- }
1029
- function readClioMdPath(filePath) {
1030
- let content;
1031
- try {
1032
- content = readFileSync2(filePath, "utf8");
1033
- } catch (err) {
1034
- return { ok: false, error: err instanceof Error ? err.message : String(err) };
1035
- }
1036
- const parsed = parseClioMd(content);
1037
- if (!parsed.ok) return { ok: false, error: parsed.errors.join("; ") };
1038
- return { ok: true, value: parsed.value };
1039
- }
1040
- function mergeClioMdFiles(files) {
1041
- const nearest = files.at(-1)?.value;
1042
- if (!nearest) return null;
1043
- return {
1044
- projectName: nearest.projectName,
1045
- identity: files.map((file) => file.value.identity).join("\n\n"),
1046
- conventions: files.flatMap((file) => file.value.conventions),
1047
- invariants: files.flatMap((file) => file.value.invariants),
1048
- sections: files.flatMap((file) => file.value.sections),
1049
- importedAgentContext: files.map((file) => file.value.importedAgentContext).filter((value) => value !== null).join("\n\n") || null,
1050
- fingerprint: nearest.fingerprint,
1051
- firstInit: nearest.firstInit,
1052
- warnings: files.flatMap((file) => file.value.warnings)
1053
- };
1054
- }
1055
- function loadProjectClioMd(cwd) {
1056
- const directories = [];
1057
- let directory = resolve2(cwd);
1058
- while (true) {
1059
- directories.unshift(directory);
1060
- const parent = dirname2(directory);
1061
- if (parent === directory) break;
1062
- directory = parent;
1063
- }
1064
- const selectedPaths = [];
1065
- for (const current of directories) {
1066
- const selected = selectedClioMdPath(current);
1067
- if (!selected) continue;
1068
- if (basename2(selected) === "CLIO-CODER.override.md") {
1069
- selectedPaths.length = 0;
1070
- }
1071
- selectedPaths.push(selected);
1072
- }
1073
- const files = [];
1074
- const errors = [];
1075
- for (const filePath of selectedPaths) {
1076
- const read = readClioMdPath(filePath);
1077
- if (read.ok) files.push({ path: filePath, value: read.value });
1078
- else errors.push({ path: filePath, error: read.error });
1079
- }
1080
- return { files, errors, value: mergeClioMdFiles(files) };
1081
- }
1082
- function tryReadClioMd(cwd) {
1083
- const filePath = join2(cwd, "CLIO-CODER.md");
1084
- if (!existsSync2(filePath)) return null;
1085
- return readClioMdPath(filePath);
1086
- }
1087
-
1088
- // src/domains/context/project-metadata.ts
1089
- init_esm_shims();
1090
- var import_yaml = __toESM(require_dist(), 1);
1091
- import { existsSync as existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync3 } from "node:fs";
1092
- import { join as join3 } from "node:path";
1093
- var MAX_DESCRIPTION_CHARS = 400;
1094
- var MAX_NAME_CHARS = 80;
1095
- function readText(cwd, relative6) {
1096
- try {
1097
- return readFileSync3(join3(cwd, relative6), "utf8");
1098
- } catch {
1099
- return null;
1100
- }
1101
- }
1102
- function clean(value, max) {
1103
- if (typeof value !== "string") return null;
1104
- const collapsed = value.replace(/\s+/gu, " ").trim();
1105
- if (collapsed.length === 0) return null;
1106
- return collapsed.length > max ? `${collapsed.slice(0, max - 1).trimEnd()}\u2026` : collapsed;
1107
- }
1108
- function name(value) {
1109
- return clean(value, MAX_NAME_CHARS);
1110
- }
1111
- function description(value) {
1112
- const cleaned = clean(value, MAX_DESCRIPTION_CHARS);
1113
- return cleaned === null ? null : clean(cleaned.replace(/\.$/u, ""), MAX_DESCRIPTION_CHARS) ?? null;
1114
- }
1115
- function jsonRecord(cwd, relative6) {
1116
- const raw = readText(cwd, relative6);
1117
- if (raw === null) return null;
1118
- try {
1119
- const parsed = JSON.parse(raw);
1120
- return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
1121
- } catch {
1122
- return null;
1123
- }
1124
- }
1125
- function keyEqualsValue(raw, key) {
1126
- const match = new RegExp(`^[ \\t]*${key}[ \\t]*(?:\\+?=)[ \\t]*(.+)$`, "mu").exec(raw);
1127
- const value = match?.[1]?.trim();
1128
- if (!value) return null;
1129
- return value.replace(/^"(.*)"$/su, "$1").trim();
1130
- }
1131
- function iniSectionValue(raw, section, key) {
1132
- const lines = raw.split(/\r?\n/u);
1133
- let inSection = false;
1134
- for (const line of lines) {
1135
- const trimmed = line.trim();
1136
- if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
1137
- inSection = trimmed === `[${section}]`;
1138
- continue;
1139
- }
1140
- if (!inSection) continue;
1141
- const match = /^([A-Za-z0-9_.-]+)\s*=\s*(.*)$/u.exec(trimmed);
1142
- if (!match || match[1] !== key) continue;
1143
- const value = (match[2] ?? "").trim();
1144
- return value.length > 0 ? value : null;
1145
- }
1146
- return null;
1147
- }
1148
- function xmlTagValue(raw, tag) {
1149
- const match = new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`, "u").exec(raw);
1150
- return match?.[1] ?? null;
1151
- }
1152
- function yamlRecord(cwd, relative6) {
1153
- const raw = readText(cwd, relative6);
1154
- if (raw === null) return null;
1155
- try {
1156
- const parsed = (0, import_yaml.parse)(raw);
1157
- return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
1158
- } catch {
1159
- return null;
1160
- }
1161
- }
1162
- var packageJson = (cwd) => {
1163
- const record = jsonRecord(cwd, "package.json");
1164
- if (!record) return null;
1165
- return { file: "package.json", fragment: { name: name(record.name), description: description(record.description) } };
1166
- };
1167
- var pyprojectToml = (_cwd, tomlFiles) => {
1168
- const document = tomlFiles.read("pyproject.toml");
1169
- if (document === null) return null;
1170
- const project = tomlTableAt(document, ["project"]);
1171
- const poetry = tomlTableAt(document, ["tool", "poetry"]);
1172
- return {
1173
- file: "pyproject.toml",
1174
- fragment: {
1175
- name: name(project?.name) ?? name(poetry?.name),
1176
- description: description(project?.description) ?? description(poetry?.description)
1177
- }
1178
- };
1179
- };
1180
- var cargoToml = (_cwd, tomlFiles) => {
1181
- const document = tomlFiles.read("Cargo.toml");
1182
- if (document === null) return null;
1183
- const packageTable = tomlTableAt(document, ["package"]);
1184
- return {
1185
- file: "Cargo.toml",
1186
- fragment: {
1187
- name: name(packageTable?.name),
1188
- description: description(packageTable?.description)
1189
- }
1190
- };
1191
- };
1192
- var setupCfg = (cwd) => {
1193
- const raw = readText(cwd, "setup.cfg");
1194
- if (raw === null) return null;
1195
- return {
1196
- file: "setup.cfg",
1197
- fragment: {
1198
- name: name(iniSectionValue(raw, "metadata", "name")),
1199
- description: description(iniSectionValue(raw, "metadata", "description"))
1200
- }
1201
- };
1202
- };
1203
- var composerJson = (cwd) => {
1204
- const record = jsonRecord(cwd, "composer.json");
1205
- if (!record) return null;
1206
- return {
1207
- file: "composer.json",
1208
- fragment: { name: name(record.name), description: description(record.description) }
1209
- };
1210
- };
1211
- var pomXml = (cwd) => {
1212
- const raw = readText(cwd, "pom.xml");
1213
- if (raw === null) return null;
1214
- return {
1215
- file: "pom.xml",
1216
- fragment: {
1217
- name: name(xmlTagValue(raw, "name") ?? xmlTagValue(raw, "artifactId")),
1218
- description: description(xmlTagValue(raw, "description"))
1219
- }
1220
- };
1221
- };
1222
- var cmakeLists = (cwd) => {
1223
- const raw = readText(cwd, "CMakeLists.txt");
1224
- if (raw === null) return null;
1225
- const call = /^[ \t]*project[ \t]*\(([\s\S]*?)\)/imu.exec(raw)?.[1];
1226
- if (!call) return { file: "CMakeLists.txt", fragment: {} };
1227
- const projectName2 = /^\s*([A-Za-z0-9_.+-]+)/u.exec(call)?.[1];
1228
- const projectDescription = /\bDESCRIPTION\s+"((?:[^"\\]|\\.)*)"/u.exec(call)?.[1];
1229
- return {
1230
- file: "CMakeLists.txt",
1231
- fragment: { name: name(projectName2), description: description(projectDescription) }
1232
- };
1233
- };
1234
- var doxyfile = (cwd) => {
1235
- for (const relative6 of ["Doxyfile", "Doxyfile.in", "docs/Doxyfile", "doc/Doxyfile"]) {
1236
- const raw = readText(cwd, relative6);
1237
- if (raw === null) continue;
1238
- return {
1239
- file: relative6,
1240
- fragment: {
1241
- name: name(keyEqualsValue(raw, "PROJECT_NAME")),
1242
- description: description(keyEqualsValue(raw, "PROJECT_BRIEF"))
1243
- }
1244
- };
1245
- }
1246
- return null;
1247
- };
1248
- var rDescription = (cwd) => {
1249
- const raw = readText(cwd, "DESCRIPTION");
1250
- if (raw === null || !/^Package:\s*\S/mu.test(raw)) return null;
1251
- const field = (key) => {
1252
- const match = new RegExp(`^${key}:[ \\t]*([\\s\\S]*?)(?=\\n\\S|$)`, "mu").exec(raw);
1253
- return match?.[1] ?? null;
1254
- };
1255
- return {
1256
- file: "DESCRIPTION",
1257
- fragment: {
1258
- name: name(field("Package")),
1259
- description: description(field("Title") ?? field("Description"))
1260
- }
1261
- };
1262
- };
1263
- var gemspec = (cwd) => {
1264
- let entries;
1265
- try {
1266
- entries = readdirSync2(cwd).filter((entry) => entry.endsWith(".gemspec"));
1267
- } catch {
1268
- return null;
1269
- }
1270
- entries.sort();
1271
- const relative6 = entries[0];
1272
- if (!relative6) return null;
1273
- const raw = readText(cwd, relative6);
1274
- if (raw === null) return null;
1275
- const field = (key) => new RegExp(`\\.${key}\\s*=\\s*["']([^"']+)["']`, "u").exec(raw)?.[1] ?? null;
1276
- return {
1277
- file: relative6,
1278
- fragment: { name: name(field("name")), description: description(field("summary") ?? field("description")) }
1279
- };
1280
- };
1281
- var citationCff = (cwd) => {
1282
- const record = yamlRecord(cwd, "CITATION.cff");
1283
- if (!record) return null;
1284
- return { file: "CITATION.cff", fragment: { name: name(record.title), description: description(record.abstract) } };
1285
- };
1286
- var codemetaJson = (cwd) => {
1287
- const record = jsonRecord(cwd, "codemeta.json");
1288
- if (!record) return null;
1289
- return { file: "codemeta.json", fragment: { name: name(record.name), description: description(record.description) } };
1290
- };
1291
- var zenodoJson = (cwd) => {
1292
- const record = jsonRecord(cwd, ".zenodo.json");
1293
- if (!record) return null;
1294
- return { file: ".zenodo.json", fragment: { name: name(record.title), description: description(record.description) } };
1295
- };
1296
- var METADATA_READERS = [
1297
- packageJson,
1298
- pyprojectToml,
1299
- cargoToml,
1300
- setupCfg,
1301
- composerJson,
1302
- pomXml,
1303
- cmakeLists,
1304
- doxyfile,
1305
- rDescription,
1306
- gemspec,
1307
- citationCff,
1308
- codemetaJson,
1309
- zenodoJson
1310
- ];
1311
- var README_CANDIDATES = [
1312
- "README.md",
1313
- "README.rst",
1314
- "README.adoc",
1315
- "README.asciidoc",
1316
- "README.org",
1317
- "README.txt",
1318
- "README.markdown",
1319
- "README",
1320
- "readme.md",
1321
- "readme.rst",
1322
- "readme.txt",
1323
- "docs/README.md",
1324
- "docs/index.rst",
1325
- "doc/README.md"
1326
- ];
1327
- function findReadme(cwd) {
1328
- for (const candidate of README_CANDIDATES) {
1329
- if (!existsSync3(join3(cwd, candidate))) continue;
1330
- const content = readText(cwd, candidate);
1331
- if (content !== null && content.trim().length > 0) return { path: candidate, content };
1332
- }
1333
- return null;
1334
- }
1335
- function stripReadmeMarkup(raw) {
1336
- return raw.replace(/<!--[\s\S]*?-->/gu, "").replace(/<picture\b[\s\S]*?<\/picture>/giu, "").replace(/^\s*<h[1-6]\b[^>]*>[\s\S]*?<\/h[1-6]>\s*$/gimu, "").replace(/\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\)/gu, "").replace(/!\[[^\]]*\]\([^)]*\)/gu, "").replace(/\[([^\]]+)\]\([^)]*\)/gu, "$1").replace(/<img\b[^>]*>/giu, "").replace(/<[^>]+>/gu, "").replace(/^\s*\.\.\s+\S+::.*(?:\n(?:[ \t]+.*)?)*/gmu, "").replace(/^\s*\.\.\s+_?\|?[^\n]*\|?:.*$/gmu, "").replace(/\|[A-Za-z0-9_-]+\|/gu, "").replace(/:[a-z]+:`([^`]*)`/gu, "$1").replace(/^\s*:[A-Za-z0-9_-]+:.*$/gmu, "").replace(/^\s*image:{1,2}[^\n]*$/gmu, "").replace(/[*_~`]/gu, "");
1337
- }
1338
- function isStructuralLine(line) {
1339
- const trimmed = line.trim();
1340
- if (trimmed.length === 0) return true;
1341
- if (/^#{1,6}\s+/u.test(trimmed)) return true;
1342
- if (/^={1,6}\s+/u.test(trimmed)) return true;
1343
- if (/^[=\-~^"'#*+_]{3,}$/u.test(trimmed)) return true;
1344
- if (/^[-|:\s]+$/u.test(trimmed)) return true;
1345
- return false;
1346
- }
1347
- function isCalloutParagraph(lines) {
1348
- const content = lines.filter((line) => line.trim().length > 0);
1349
- if (content.length === 0) return false;
1350
- return content.every((line) => /^\s*>/u.test(line));
1351
- }
1352
- function readmeSummary(content) {
1353
- const paragraphs = stripReadmeMarkup(content).split(/\n\s*\n/u).map((part) => part.split(/\r?\n/u)).filter((lines) => !isCalloutParagraph(lines)).map(
1354
- (lines) => lines.filter((line) => !isStructuralLine(line)).join(" ").trim()
1355
- ).filter(
1356
- (part) => part.length >= 20 && /[A-Za-z]{3}/u.test(part) && !part.startsWith("```") && !/^table of contents$/iu.test(part)
1357
- );
1358
- const first = paragraphs[0];
1359
- if (!first) return null;
1360
- return description(first);
1361
- }
1362
- function readmeTitle(content) {
1363
- const lines = stripReadmeMarkup(content).split(/\r?\n/u);
1364
- for (let index = 0; index < lines.length; index += 1) {
1365
- const line = (lines[index] ?? "").trim();
1366
- if (line.length === 0) continue;
1367
- const hash = /^#{1,3}\s+(.+?)\s*$/u.exec(line)?.[1] ?? /^={1,3}\s+(.+?)\s*$/u.exec(line)?.[1];
1368
- if (hash) return name(hash);
1369
- const next = (lines[index + 1] ?? "").trim();
1370
- if (/^[=\-~^]{3,}$/u.test(next) && !isStructuralLine(line)) return name(line);
1371
- return null;
1372
- }
1373
- return null;
1374
- }
1375
- function readProjectMetadata(cwd, tomlFiles = createTomlFileReader(cwd)) {
1376
- const out3 = { name: null, description: null, nameSource: null, descriptionSource: null };
1377
- for (const reader of METADATA_READERS) {
1378
- if (out3.name !== null && out3.description !== null) break;
1379
- let read;
1380
- try {
1381
- read = reader(cwd, tomlFiles);
1382
- } catch {
1383
- continue;
1384
- }
1385
- if (!read) continue;
1386
- if (out3.name === null && read.fragment.name) {
1387
- out3.name = read.fragment.name;
1388
- out3.nameSource = read.file;
1389
- }
1390
- if (out3.description === null && read.fragment.description) {
1391
- out3.description = read.fragment.description;
1392
- out3.descriptionSource = read.file;
1393
- }
1394
- }
1395
- if (out3.name !== null && out3.description !== null) return out3;
1396
- const readme = findReadme(cwd);
1397
- if (!readme) return out3;
1398
- if (out3.name === null) {
1399
- const title = readmeTitle(readme.content);
1400
- if (title) {
1401
- out3.name = title;
1402
- out3.nameSource = readme.path;
1403
- }
1404
- }
1405
- if (out3.description === null) {
1406
- const summary = readmeSummary(readme.content);
1407
- if (summary) {
1408
- out3.description = summary;
1409
- out3.descriptionSource = readme.path;
1410
- }
1411
- }
1412
- return out3;
1413
- }
1414
-
1415
- // src/domains/context/prompt-context.ts
1416
- init_esm_shims();
1417
- var HANDBOOK_ABSENT_FRAGMENT = "<handbook>none: this workspace has no CLIO-CODER.md, so do not read one; learn the repository from its files, and the operator can run /context init to write a handbook</handbook>";
1418
- function renderPromptContext(cwd) {
1419
- const projectType = detectProjectType(cwd);
1420
- const pieces = [renderProjectTypeFragment(projectType)];
1421
- const warnings = [];
1422
- const loadedClioMd = loadProjectClioMd(cwd);
1423
- const clioMd = loadedClioMd.value;
1424
- for (const file of loadedClioMd.files) pieces.push(renderProjectContextFragment(file.value, file.path));
1425
- for (const issue of loadedClioMd.errors) {
1426
- warnings.push(`clio-coder: malformed ${issue.path} ignored: ${issue.error}`);
1427
- }
1428
- if (loadedClioMd.files.length === 0 && loadedClioMd.errors.length === 0) pieces.push(HANDBOOK_ABSENT_FRAGMENT);
1429
- const codewiki = readCodewiki(cwd);
1430
- if (codewiki) {
1431
- const state = readClioState(cwd);
1432
- const stale = state ? isStale(state.fingerprint, computeFingerprintCached(cwd, codewiki)) : true;
1433
- const suffix = stale ? " (stale; run /context refresh)" : "";
1434
- pieces.push(`<codewiki>available${suffix}; use code_nav</codewiki>`);
1435
- }
1436
- const staleness = wikiStaleness(cwd);
1437
- if (staleness.state !== "absent") {
1438
- const pages = listWikiPages(cwd);
1439
- const completeness = wikiCompleteness(cwd);
1440
- const notes = [];
1441
- if (completeness && completeness.owed > 0) {
1442
- notes.push(
1443
- `incomplete: ${completeness.pagesWritten} of ${completeness.pagesPlanned} planned pages written, ${completeness.owed} owed`
1444
- );
1445
- }
1446
- if (staleness.state === "stale") notes.push("stale");
1447
- const suffix = notes.length > 0 ? ` (${notes.join("; ")}; run clio-coder context wiki --update)` : "";
1448
- pieces.push(`<wiki>${pages.length} pages at .clio-coder/wiki (start: quickstart.md)${suffix}</wiki>`);
1449
- }
1450
- return { text: pieces.join("\n\n"), clioMd, warnings, handbookFiles: loadedClioMd.files.map((file) => file.path) };
1451
- }
1452
-
1453
- // src/domains/context/bootstrap.ts
1454
- function out(io, message) {
1455
- io?.stdout(message);
1456
- }
1457
- function warn(io, message) {
1458
- io?.stderr(message);
1459
- }
1460
- function progress(input, event) {
1461
- input.onProgress?.(event);
1462
- }
1463
- function readJsonFile(filePath) {
1464
- try {
1465
- return JSON.parse(readFileSync4(filePath, "utf8"));
1466
- } catch {
1467
- return null;
1468
- }
1469
- }
1470
- function stringField2(value, key) {
1471
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
1472
- const field = value[key];
1473
- return typeof field === "string" && field.trim().length > 0 ? field.trim() : null;
1474
- }
1475
- function titleFromPackageName(raw) {
1476
- const base = raw.includes("/") ? raw.split("/").pop() ?? raw : raw;
1477
- return base.split(/[-_]+/).filter(Boolean).map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`).join(" ");
1478
- }
1479
- function projectNameFrom(metadata, cwd) {
1480
- const declared = metadata.name;
1481
- if (declared) {
1482
- return metadata.nameSource === "package.json" ? titleFromPackageName(declared) : declared.slice(0, 80);
1483
- }
1484
- return titleFromPackageName(parse(cwd).base || "Project");
1485
- }
1486
- function projectName(cwd, tomlFiles) {
1487
- return projectNameFrom(readProjectMetadata(cwd, tomlFiles), cwd);
1488
- }
1489
- function projectTypeLabel(projectType) {
1490
- switch (projectType) {
1491
- case "typescript":
1492
- return "TypeScript/Node.js";
1493
- case "javascript":
1494
- return "JavaScript/Node.js";
1495
- case "python":
1496
- return "Python";
1497
- case "rust":
1498
- return "Rust";
1499
- case "go":
1500
- return "Go";
1501
- case "c":
1502
- return "C";
1503
- case "c++":
1504
- return "C++";
1505
- case "java":
1506
- return "Java";
1507
- case "ruby":
1508
- return "Ruby";
1509
- case "c#":
1510
- return "C#";
1511
- case "polyglot":
1512
- return "polyglot";
1513
- case "dotfiles":
1514
- return "dotfiles";
1515
- case "unknown":
1516
- return "software";
1517
- }
1518
- }
1519
- function allContextText(files) {
1520
- return files.map((file) => file.content).join("\n\n");
1521
- }
1522
- function resolveDefaultIdentity(cwd, projectType, files, tomlFiles) {
1523
- const metadata = readProjectMetadata(cwd, tomlFiles);
1524
- const name2 = projectNameFrom(metadata, cwd);
1525
- const context = allContextText(files);
1526
- if (/Clio owns the agent loop/i.test(context) && /pi-(?:ai|SDK)/i.test(context)) {
1527
- return {
1528
- text: [
1529
- "Clio Coder is IOWarp's orchestrator coding agent, named for the Greek muse of history and developed by the Gnosis Research Center at Illinois Tech (github.com/grc-iit, @grc-iit) and the IOWarp team. CLIO stands for Context Layer for Input/Output.",
1530
- "pi-ai is accessed through the engine boundary.",
1531
- "Clio owns the agent loop, TUI, session format, tool registry, and identity."
1532
- ].join(" "),
1533
- bare: false,
1534
- descriptionSource: null
1535
- };
1536
- }
1537
- const stack = projectTypeLabel(projectType);
1538
- const head = `${name2} is a ${stack} project.`;
1539
- const description2 = metadata.description;
1540
- if (!description2) return { text: head.slice(0, 600), bare: true, descriptionSource: null };
1541
- const cleaned = description2.replace(/\.$/, "").trim();
1542
- const role = /^[a-z]/.test(cleaned) ? `It is ${cleaned}.` : `${cleaned}.`;
1543
- return { text: `${head} ${role}`.slice(0, 600), bare: false, descriptionSource: metadata.descriptionSource };
1544
- }
1545
- function stabilizedIdentity(input, modelIdentity, tomlFiles) {
1546
- const deterministic = resolveDefaultIdentity(input.cwd, input.projectType, input.siblingFiles, tomlFiles);
1547
- const model = typeof modelIdentity === "string" ? modelIdentity.trim() : "";
1548
- if (deterministic.bare && model.length > 0) return model;
1549
- return deterministic.text;
1550
- }
1551
- function pushUnique(target, value) {
1552
- if (target.includes(value)) return;
1553
- target.push(value);
1554
- }
1555
- var SKIP_BULLET_PATTERNS = [/^marker\s*[:=]/i, /marker[-_:]\s*\w+-\w+/i, /^todo\b/i, /^note\b/i, /^example\b/i];
1556
- function harvestSiblingBullets(files) {
1557
- const out3 = [];
1558
- for (const file of files) {
1559
- for (const rawLine of file.content.split("\n")) {
1560
- const match = /^[\s>]*[-*]\s+(.+?)\s*$/.exec(rawLine);
1561
- if (!match) continue;
1562
- const bullet = match[1]?.trim();
1563
- if (!bullet || bullet.length < 5) continue;
1564
- if (bullet.length > 200) continue;
1565
- if (SKIP_BULLET_PATTERNS.some((re) => re.test(bullet))) continue;
1566
- if (!RULE_KEYWORDS.test(bullet)) continue;
1567
- out3.push(bullet);
1568
- }
1569
- }
1570
- return out3;
1571
- }
1572
- function localImportExtension(codewiki) {
1573
- const counts = /* @__PURE__ */ new Map();
1574
- let total = 0;
1575
- for (const file of codewiki.files) {
1576
- for (const specifier of file.imports) {
1577
- if (!specifier.startsWith(".")) continue;
1578
- total += 1;
1579
- const extension = /\.([A-Za-z0-9]+)$/.exec(specifier)?.[1];
1580
- const key = extension === void 0 ? "" : `.${extension}`;
1581
- counts.set(key, (counts.get(key) ?? 0) + 1);
1582
- }
1583
- }
1584
- if (total < 4) return null;
1585
- for (const [extension, count] of counts) {
1586
- if (extension.length > 0 && count / total >= 0.8) return extension;
1587
- }
1588
- return null;
1589
- }
1590
- function inferConventions(cwd, files, codewiki) {
1591
- const conventions = [];
1592
- const context = allContextText(files);
1593
- const pkg = readJsonFile(join4(cwd, "package.json"));
1594
- const packageText = typeof pkg === "object" && pkg !== null ? JSON.stringify(pkg) : "";
1595
- const declaredJs = /Local imports end in `?\.js`?/i.test(context);
1596
- const importExtension = declaredJs ? ".js" : localImportExtension(codewiki);
1597
- if (importExtension !== null) {
1598
- pushUnique(conventions, `Local imports end in \`${importExtension}\`.`);
1599
- }
1600
- if (/node:test/i.test(context) || /node --import tsx --test|node --test/.test(packageText)) {
1601
- pushUnique(conventions, "Tests use `node:test`.");
1602
- }
1603
- if (/No em-dash|em-dash/i.test(context)) {
1604
- pushUnique(
1605
- conventions,
1606
- "No em-dash clause separators in code, comments, commits, or responses. Write full sentences."
1607
- );
1608
- }
1609
- if (/Commit subjects|conventional commit|Imperative, lowercase|lowercase-typed subjects/i.test(context)) {
1610
- pushUnique(
1611
- conventions,
1612
- "Commit subjects are imperative, lowercase, conventional, at most 72 characters, and end without a period."
1613
- );
1614
- }
1615
- for (const bullet of harvestSiblingBullets(files)) pushUnique(conventions, bullet);
1616
- return conventions.slice(0, 6);
1617
- }
1618
- function inferInvariants(files) {
1619
- const context = allContextText(files);
1620
- const invariants = [];
1621
- if (/Engine boundary/i.test(context)) {
1622
- pushUnique(invariants, "Engine boundary. Only `src/engine/**` may value-import `@earendil-works/pi-*`.");
1623
- }
1624
- if (/Worker isolation/i.test(context)) {
1625
- pushUnique(
1626
- invariants,
1627
- "Worker isolation. `src/worker/**` never imports `src/domains/**` except `src/domains/providers`."
1628
- );
1629
- }
1630
- if (/Domain independence/i.test(context)) {
1631
- pushUnique(
1632
- invariants,
1633
- "Domain independence. `src/domains/<x>/**` never imports `src/domains/<y>/extension.ts` for `y != x`."
1634
- );
1635
- }
1636
- return invariants.slice(0, 3);
1637
- }
1638
- function indexedSourceFileCount(codewiki) {
1639
- return codewiki.files.filter((file) => file.lang !== "config").length;
1640
- }
1641
- function measureProjectPreload(cwd) {
1642
- const promptContext = renderPromptContext(cwd);
1643
- return classifyProjectPreload({ hasClioMd: promptContext.clioMd !== null, text: promptContext.text });
1644
- }
1645
- function packageScripts(cwd) {
1646
- const pkg = readJsonFile(join4(cwd, "package.json"));
1647
- if (typeof pkg !== "object" || pkg === null || Array.isArray(pkg)) return {};
1648
- const scripts = pkg.scripts;
1649
- if (typeof scripts !== "object" || scripts === null || Array.isArray(scripts)) return {};
1650
- const out3 = {};
1651
- for (const [name2, command] of Object.entries(scripts)) {
1652
- if (typeof command === "string" && command.trim().length > 0) out3[name2] = command.trim();
1653
- }
1654
- return out3;
1655
- }
1656
- function packageManager(cwd) {
1657
- const declared = stringField2(readJsonFile(join4(cwd, "package.json")), "packageManager")?.split("@")[0];
1658
- if (declared === "pnpm" || declared === "yarn" || declared === "bun" || declared === "npm") return declared;
1659
- if (existsSync4(join4(cwd, "pnpm-lock.yaml"))) return "pnpm";
1660
- if (existsSync4(join4(cwd, "yarn.lock"))) return "yarn";
1661
- if (existsSync4(join4(cwd, "bun.lock")) || existsSync4(join4(cwd, "bun.lockb"))) return "bun";
1662
- return "npm";
1663
- }
1664
- var MUTATING_SCRIPT_RE = /(?:^|\s)--(?:fix|write)(?:\s|$)/;
1665
- function cmakePresetName(presets, key) {
1666
- if (typeof presets !== "object" || presets === null || Array.isArray(presets)) return null;
1667
- const list = presets[key];
1668
- if (!Array.isArray(list)) return null;
1669
- for (const entry of list) {
1670
- if (entry?.hidden === true) continue;
1671
- const name2 = stringField2(entry, "name");
1672
- if (name2 !== null) return name2;
1673
- }
1674
- return null;
1675
- }
1676
- function cmakeVerificationLines(cwd) {
1677
- const presets = readJsonFile(join4(cwd, "CMakePresets.json"));
1678
- if (presets === null) return [];
1679
- const configure = cmakePresetName(presets, "configurePresets");
1680
- const build = cmakePresetName(presets, "buildPresets");
1681
- const test = cmakePresetName(presets, "testPresets");
1682
- const lines = [];
1683
- if (configure !== null) lines.push(`Configure with \`cmake --preset ${configure}\`.`);
1684
- if (build !== null) lines.push(`Build with \`cmake --build --preset ${build}\`.`);
1685
- if (test !== null) lines.push(`Run tests with \`ctest --preset ${test}\`.`);
1686
- return lines;
1687
- }
1688
- function pythonVerificationLines(cwd, tomlFiles) {
1689
- const pyproject = tomlFiles.read("pyproject.toml");
1690
- if (existsSync4(join4(cwd, "tox.ini")) || pyproject !== null && tomlTableAt(pyproject, ["tool", "tox"])) {
1691
- return ["Run `tox` before handoff."];
1692
- }
1693
- if (existsSync4(join4(cwd, "pytest.ini")) || pyproject !== null && tomlTableAt(pyproject, ["tool", "pytest", "ini_options"])) {
1694
- return ["Run `pytest` before handoff."];
1695
- }
1696
- return [];
1697
- }
1698
- function verificationSection(cwd, tomlFiles) {
1699
- const scripts = packageScripts(cwd);
1700
- const pm = packageManager(cwd);
1701
- const hasScript = (name2) => typeof scripts[name2] === "string";
1702
- const command = (name2) => `\`${pm} run ${name2}\``;
1703
- const gate = (name2) => {
1704
- if (hasScript(`${name2}:check`)) return `${name2}:check`;
1705
- return hasScript(name2) && !MUTATING_SCRIPT_RE.test(scripts[name2] ?? "") ? name2 : null;
1706
- };
1707
- const lines = [];
1708
- const baseline = ["typecheck", "lint", "format"].map(gate).filter((name2) => name2 !== null).map(command);
1709
- if (baseline.length > 0) {
1710
- lines.push(`Before handoff, run ${baseline.join(", ")}.`);
1711
- }
1712
- if (hasScript("build")) {
1713
- lines.push(`Run ${command("build")} after CLI, worker, packaging, or generated-dist changes.`);
1714
- }
1715
- const targeted = ["test:contracts", "test:smoke", "check:boundaries"].filter(hasScript).map(command);
1716
- if (targeted.length > 0) {
1717
- lines.push(`Use targeted checks for narrower risk: ${targeted.join(", ")}.`);
1718
- }
1719
- if (hasScript("test")) {
1720
- lines.push(`Run ${command("test")} when behavior crosses domains, tool contracts, smoke flows, or boundaries.`);
1721
- }
1722
- if (hasScript("ci")) {
1723
- lines.push(`Use ${command("ci")} for the full local gate before committing broad or shared behavior changes.`);
1724
- }
1725
- lines.push(...cmakeVerificationLines(cwd));
1726
- const cargo = tomlFiles.read("Cargo.toml");
1727
- if (cargo !== null && (tomlTableAt(cargo, ["package"]) || tomlTableAt(cargo, ["workspace"]))) {
1728
- lines.push("Run `cargo build` and `cargo test` before handoff.");
1729
- }
1730
- if (existsSync4(join4(cwd, "go.mod"))) {
1731
- lines.push("Run `go build ./...` and `go test ./...` before handoff.");
1732
- }
1733
- lines.push(...pythonVerificationLines(cwd, tomlFiles));
1734
- if (lines.length === 0) return null;
1735
- return { title: "Verification expectations", body: lines.join(" ") };
1736
- }
1737
- var VERIFICATION_SECTION_RE = /\bverification\b/i;
1738
- function createModelGroundingCorpus(input) {
1739
- let siblingBudget = 64e3;
1740
- const siblingEvidence = [];
1741
- for (const file of input.siblingFiles) {
1742
- if (siblingBudget <= 0) break;
1743
- const chunk = file.content.slice(0, siblingBudget);
1744
- siblingEvidence.push(chunk);
1745
- siblingBudget -= chunk.length;
1746
- }
1747
- const indexedPaths = new Set(input.codewiki.files.map((file) => file.path));
1748
- const pm = packageManager(input.cwd);
1749
- const scripts = packageScripts(input.cwd);
1750
- const evidence = [
1751
- ...siblingEvidence,
1752
- (input.existingClioMdText ?? "").slice(0, 8e3),
1753
- input.expectedProjectName ?? "",
1754
- input.projectType,
1755
- [...indexedPaths].join("\n").slice(0, 64e3),
1756
- ...Object.entries(scripts).flatMap(([name2, command]) => [`${pm} run ${name2}`, `${pm} ${name2}`, command]),
1757
- input.codewiki.symbols.map((symbol) => symbol.name).join("\n").slice(0, 128e3)
1758
- ].join("\n");
1759
- return { lower: evidence.toLowerCase(), indexedPaths };
1760
- }
1761
- var CODE_TOKEN_RE = /`([^`\n]+)`/g;
1762
- var CITED_LOCATION_RE = /^(.*[^:]):(\d+)(?:[-:]\d+)?$/;
1763
- var CITED_CALL_RE = /^(.+?)\(\s*\)$/;
1764
- function groundedName(token, evidence) {
1765
- return evidence.lower.includes(token.toLowerCase()) || evidence.indexedPaths.has(token.replace(/^\.\//, ""));
1766
- }
1767
- function citedNames(token) {
1768
- const names = [];
1769
- let current = token;
1770
- for (let round = 0; round < 2; round += 1) {
1771
- const next = (CITED_CALL_RE.exec(current)?.[1] ?? CITED_LOCATION_RE.exec(current)?.[1])?.trim();
1772
- if (next === void 0 || next.length === 0 || next === current) break;
1773
- names.push(next);
1774
- current = next;
1775
- }
1776
- return names;
1777
- }
1778
- function groundedToken(token, evidence) {
1779
- return groundedName(token, evidence) || citedNames(token).some((name2) => groundedName(name2, evidence));
1780
- }
1781
- function groundedModelBody(body, evidence) {
1782
- const kept = [];
1783
- let inFence = false;
1784
- for (const rawLine of body.split(/\r?\n/)) {
1785
- const trimmed = rawLine.trim();
1786
- if (trimmed.startsWith("```")) {
1787
- inFence = !inFence;
1788
- continue;
1789
- }
1790
- if (trimmed.length === 0 || /^#{1,6}\s|^---+$/.test(trimmed)) continue;
1791
- const line = inFence ? `\`${trimmed.replace(/`/g, "")}\`` : trimmed;
1792
- const codeTokens = [...line.matchAll(CODE_TOKEN_RE)].map((match) => match[1]?.trim()).filter((token) => token !== void 0 && token.length > 0);
1793
- if (codeTokens.length === 0) continue;
1794
- if (!codeTokens.every((token) => groundedToken(token, evidence))) continue;
1795
- if (line.replace(CODE_TOKEN_RE, "").trim().length === 0 && !inFence) continue;
1796
- kept.push(line);
1797
- }
1798
- const bounded = [];
1799
- let length = 0;
1800
- for (const line of kept) {
1801
- const nextLength = length + (bounded.length > 0 ? 1 : 0) + line.length;
1802
- if (nextLength > 1200) break;
1803
- bounded.push(line);
1804
- length = nextLength;
1805
- }
1806
- return bounded.join("\n").trim();
1807
- }
1808
- function sanitizeModelSection(section, evidence) {
1809
- const body = groundedModelBody(section.body, evidence);
1810
- if (body.length < 40) return null;
1811
- const title = section.title.replace(/\s+/g, " ").trim();
1812
- return title.length > 0 ? { title, body } : null;
1813
- }
1814
- function stabilizeGeneratedOutput(input, base, onModelSectionRetained, groundModelOutput = false) {
1815
- const tomlFiles = input.tomlFiles ?? createTomlFileReader(input.cwd);
1816
- const existing = input.existingClioMd;
1817
- const conventions = [];
1818
- for (const convention of existing?.conventions ?? []) pushUnique(conventions, convention);
1819
- for (const convention of inferConventions(input.cwd, input.siblingFiles, input.codewiki)) {
1820
- pushUnique(conventions, convention);
1821
- }
1822
- const invariants = [];
1823
- for (const invariant of existing?.invariants ?? []) pushUnique(invariants, invariant);
1824
- for (const invariant of inferInvariants(input.siblingFiles)) pushUnique(invariants, invariant);
1825
- const verification = verificationSection(input.cwd, tomlFiles);
1826
- const inferredSections = inferHeuristicSections(input);
1827
- const existingSections = existing?.sections ?? [];
1828
- const ordinarySections = [];
1829
- const modelSections = /* @__PURE__ */ new Set();
1830
- const seenSectionTitles = /* @__PURE__ */ new Set();
1831
- const addSection = (section) => {
1832
- if (VERIFICATION_SECTION_RE.test(section.title)) return false;
1833
- const titleKey = section.title.replace(/\s+/g, " ").trim().toLowerCase();
1834
- if (seenSectionTitles.has(titleKey)) return false;
1835
- seenSectionTitles.add(titleKey);
1836
- ordinarySections.push(section);
1837
- return true;
1838
- };
1839
- for (const section of existing ? [...existingSections, ...inferredSections] : inferredSections) addSection(section);
1840
- const groundingCorpus = groundModelOutput ? createModelGroundingCorpus(input) : null;
1841
- for (const section of base.sections ?? []) {
1842
- const sanitized = groundingCorpus ? sanitizeModelSection(section, groundingCorpus) : section;
1843
- if (sanitized && addSection(sanitized)) modelSections.add(sanitized);
1844
- }
1845
- const ordinaryLimit = verification ? 6 : 7;
1846
- const retainedOrdinarySections = ordinarySections.slice(0, ordinaryLimit);
1847
- for (const section of retainedOrdinarySections) {
1848
- if (modelSections.has(section)) onModelSectionRetained?.();
1849
- }
1850
- return {
1851
- ...base,
1852
- projectName: existing?.projectName ?? projectName(input.cwd, tomlFiles),
1853
- identity: existing?.identity ?? stabilizedIdentity(input, base.identity, tomlFiles),
1854
- conventions: conventions.slice(0, 6),
1855
- invariants: invariants.slice(0, 3),
1856
- sections: [...retainedOrdinarySections, ...verification ? [verification] : []]
1857
- };
1858
- }
1859
- function codewikiSections(codewiki) {
1860
- const sections = [];
1861
- const entryPoints = codewikiEntryPoints(codewiki, 8);
1862
- if (entryPoints.length > 0) {
1863
- sections.push({
1864
- title: "Context retrieval",
1865
- body: [
1866
- `Start orientation with these indexed entry points: ${entryPoints.map((entry) => `\`${entry}\``).join(", ")}.`,
1867
- "Use `code_nav` (modes: symbol, path, entries, outline, deps, dependents, wiki) before broad reads when the task is navigational."
1868
- ].join(" ")
1869
- });
1870
- }
1871
- return sections;
1872
- }
1873
- function inferHeuristicSections(input) {
1874
- const sections = [...codewikiSections(input.codewiki)];
1875
- const invariants = inferInvariants(input.siblingFiles);
1876
- if (invariants.length > 0) {
1877
- sections.push({
1878
- title: "Architecture boundaries",
1879
- body: invariants.map((item) => `- ${item}`).join("\n")
1880
- });
1881
- }
1882
- if (input.adoption.sources.length > 0) {
1883
- const sourceNames = input.adoption.sources.map((source) => `\`${source.displayPath}\``).slice(0, 8).join(", ");
1884
- sections.push({
1885
- title: "Agent context interop",
1886
- body: [
1887
- `Bootstrap scanned ${input.adoption.sources.length} sibling context source${input.adoption.sources.length === 1 ? "" : "s"}: ${sourceNames}${input.adoption.sources.length > 8 ? ", ..." : ""}.`,
1888
- "Run `clio-coder context init --adopt` to refresh the managed provenance section when those sources change."
1889
- ].join(" ")
1890
- });
1891
- }
1892
- return sections.slice(0, 6);
1893
- }
1894
- function heuristicBootstrapOutputSync(input) {
1895
- const tomlFiles = input.tomlFiles ?? createTomlFileReader(input.cwd);
1896
- const sharedInput = input.tomlFiles ? input : { ...input, tomlFiles };
1897
- return stabilizeGeneratedOutput(sharedInput, {
1898
- projectName: projectName(input.cwd, tomlFiles),
1899
- identity: resolveDefaultIdentity(input.cwd, input.projectType, input.siblingFiles, tomlFiles).text,
1900
- conventions: inferConventions(input.cwd, input.siblingFiles, input.codewiki),
1901
- invariants: inferInvariants(input.siblingFiles),
1902
- sections: inferHeuristicSections(input)
1903
- });
1904
- }
1905
- var heuristicBootstrapOutput = heuristicBootstrapOutputSync;
1906
- function bootstrapOutputFromParsed(parsed) {
1907
- const out3 = {
1908
- projectName: parsed.projectName,
1909
- identity: parsed.identity,
1910
- conventions: [...parsed.conventions],
1911
- invariants: [...parsed.invariants]
1912
- };
1913
- if (parsed.sections.length > 0) {
1914
- out3.sections = parsed.sections.map((section) => ({ title: section.title, body: section.body }));
1915
- }
1916
- if (parsed.importedAgentContext) out3.importedAgentContext = parsed.importedAgentContext;
1917
- return out3;
1918
- }
1919
- function existingClioMdBootstrapOutput(cwd) {
1920
- const parsed = tryReadClioMd(cwd);
1921
- if (!parsed?.ok) return null;
1922
- return bootstrapOutputFromParsed(parsed.value);
1923
- }
1924
- function fallbackBootstrapOutput(input) {
1925
- const existing = input.existingClioMd ? bootstrapOutputFromParsed(input.existingClioMd) : existingClioMdBootstrapOutput(input.cwd);
1926
- if (existing) return { mode: "existing", output: existing };
1927
- return { mode: "heuristic", output: heuristicBootstrapOutputSync(input) };
1928
- }
1929
- function readExistingClioMdText(cwd) {
1930
- try {
1931
- return readFileSync4(join4(cwd, "CLIO-CODER.md"), "utf8");
1932
- } catch {
1933
- return null;
1934
- }
1935
- }
1936
- function replaceImportedAgentContext(output, importedAgentContext) {
1937
- const { importedAgentContext: _old, ...rest } = output;
1938
- if (importedAgentContext.length === 0) return rest;
1939
- return { ...rest, importedAgentContext };
1940
- }
1941
- function loadBootstrapSiblingFiles(adoption) {
1942
- return adoption.sources.map((source) => ({
1943
- source: source.scope,
1944
- path: source.path,
1945
- content: source.content
1946
- }));
1947
- }
1948
- function gitStatus(cwd) {
1949
- try {
1950
- return execFileSync("git", ["status", "--short"], {
1951
- cwd,
1952
- encoding: "utf8",
1953
- stdio: ["ignore", "pipe", "ignore"]
1954
- });
1955
- } catch {
1956
- return "";
1957
- }
1958
- }
1959
- function countStatusLines(status) {
1960
- return status.split("\n").map((line) => line.trim()).filter(Boolean).length;
1961
- }
1962
- function basenameList(paths) {
1963
- const names = paths.map((path) => parse(path).base).sort((a, b) => a.localeCompare(b));
1964
- if (names.length === 0) return "";
1965
- if (names.length <= 3) return names.join(", ");
1966
- return `${names.slice(0, 3).join(", ")} +${names.length - 3}`;
1967
- }
1968
- function formatAdoptionLine(summary) {
1969
- const adoption = summary.adoption;
1970
- const shouldRender = summary.action === "previewed" || adoption.mode === "adopt" || adoption.globalSourceCount > 0 || adoption.conflictCount > 0 || adoption.rejectedCount > 0;
1971
- if (!shouldRender) return null;
1972
- const global = adoption.includeGlobal ? `${adoption.globalSourceCount} global` : "global off";
1973
- const verb = adoption.mode === "adopt" ? "imported" : "scanned";
1974
- return ` adoption ${verb} ${adoption.sourceCount} source${adoption.sourceCount === 1 ? "" : "s"} (${adoption.projectSourceCount} project, ${global}); ${adoption.importedRuleCount} candidate rule${adoption.importedRuleCount === 1 ? "" : "s"}; ${adoption.conflictCount} conflict${adoption.conflictCount === 1 ? "" : "s"}; ${adoption.rejectedCount} rejected`;
1975
- }
1976
- function formatBootstrapSummary(summary) {
1977
- const contextLine = summary.contextFileCount > 0 ? `folded ${summary.contextFileCount} context file${summary.contextFileCount === 1 ? "" : "s"} (${basenameList(summary.contextFileNames)})` : "no sibling context files found";
1978
- const dirtyLine = summary.dirtyFiles === 0 ? "workspace clean" : `workspace has ${summary.dirtyFiles} dirty file${summary.dirtyFiles === 1 ? "" : "s"}`;
1979
- if (summary.action === "previewed") {
1980
- const adoptionLine2 = formatAdoptionLine(summary);
1981
- return [
1982
- "clio-coder context init preview",
1983
- ` ${contextLine}; codewiki would index ${summary.codewikiEntries} entr${summary.codewikiEntries === 1 ? "y" : "ies"}; ${dirtyLine}; no files written`,
1984
- ...adoptionLine2 ? [adoptionLine2] : [],
1985
- ""
1986
- ].join("\n");
1987
- }
1988
- const adoptionLine = formatAdoptionLine(summary);
1989
- const proposalLine = summary.proposalPath ? ` proposal written ${summary.proposalPath}` : null;
1990
- if (summary.action === "preserved") {
1991
- return [
1992
- "clio-coder context init preserved CLIO-CODER.md",
1993
- ` ${contextLine}; codewiki rebuilt ${summary.codewikiEntries} entr${summary.codewikiEntries === 1 ? "y" : "ies"}; state refreshed; ${dirtyLine}`,
1994
- " CLIO-CODER.md is treated as human-owned. Use --apply to replace it with a generated draft, --propose to write an ignored proposal, or --adopt to refresh only imported agent context.",
1995
- ...adoptionLine ? [adoptionLine] : [],
1996
- ""
1997
- ].join("\n");
1998
- }
1999
- if (summary.action === "proposed") {
2000
- return [
2001
- "clio-coder context init proposed CLIO-CODER.md",
2002
- ` ${contextLine}; codewiki rebuilt ${summary.codewikiEntries} entr${summary.codewikiEntries === 1 ? "y" : "ies"}; state refreshed; ${dirtyLine}`,
2003
- ...proposalLine ? [proposalLine] : [],
2004
- " CLIO-CODER.md was not changed. Re-run with --apply only after reviewing the proposal.",
2005
- ...adoptionLine ? [adoptionLine] : [],
2006
- ""
2007
- ].join("\n");
2008
- }
2009
- return [
2010
- `clio-coder context init ${summary.action} CLIO-CODER.md`,
2011
- ` ${contextLine}; codewiki rebuilt ${summary.codewikiEntries} entr${summary.codewikiEntries === 1 ? "y" : "ies"}; state refreshed; ${dirtyLine}`,
2012
- " git policy: .clio-coder/ stays ignored by default; CLIO-CODER.md stays versioned and human-owned. Force-add .clio-coder assets only when you explicitly intend to share them.",
2013
- ...proposalLine ? [proposalLine] : [],
2014
- ...adoptionLine ? [adoptionLine] : [],
2015
- ""
2016
- ].join("\n");
2017
- }
2018
- var CLIO_GITIGNORE_LINE = ".clio-coder/";
2019
- var CLIO_GITIGNORE_DYNAMIC_LINES = /* @__PURE__ */ new Set([
2020
- ".clio-coder/codewiki.json",
2021
- ".clio-coder/state.json",
2022
- ".clio-coder/handoffs/"
2023
- ]);
2024
- function normalizedGitignoreLines(content) {
2025
- return content.split(/\r?\n/).map((line) => line.trim());
2026
- }
2027
- function hasBlanketClioIgnore(content) {
2028
- return normalizedGitignoreLines(content).some(isBlanketClioIgnoreLine);
2029
- }
2030
- function isBlanketClioIgnoreLine(line) {
2031
- if (line.length === 0 || line.startsWith("#") || line.startsWith("!")) return false;
2032
- return /^(?:\/|\*\*\/)?\.clio-coder(?:\/|\/\*|\/\*\*)?$/.test(line);
2033
- }
2034
- function hasDynamicOnlyClioIgnore(content) {
2035
- const lines = new Set(normalizedGitignoreLines(content));
2036
- for (const line of CLIO_GITIGNORE_DYNAMIC_LINES) {
2037
- if (!lines.has(line)) return false;
2038
- }
2039
- return true;
2040
- }
2041
- function migrateClioGitignore(content) {
2042
- const lines = content.split(/\r?\n/);
2043
- const kept = lines.filter((line) => {
2044
- const trimmed = line.trim();
2045
- return !isBlanketClioIgnoreLine(trimmed) && !CLIO_GITIGNORE_DYNAMIC_LINES.has(trimmed);
2046
- });
2047
- while (kept.length > 0 && kept[kept.length - 1]?.trim() === "") kept.pop();
2048
- const prefix = kept.length > 0 ? [...kept, ""] : [];
2049
- return `${[...prefix, CLIO_GITIGNORE_LINE].join("\n")}
2050
- `;
2051
- }
2052
- async function ensureGitignore(cwd, input) {
2053
- const gitignorePath = join4(cwd, ".gitignore");
2054
- let content = "";
2055
- try {
2056
- content = readFileSync4(gitignorePath, "utf8");
2057
- } catch {
2058
- content = "";
2059
- }
2060
- if (hasBlanketClioIgnore(content)) {
2061
- if (hasDynamicOnlyClioIgnore(content)) writeFileSync(gitignorePath, migrateClioGitignore(content), "utf8");
2062
- return;
2063
- }
2064
- if (hasDynamicOnlyClioIgnore(content)) {
2065
- writeFileSync(gitignorePath, migrateClioGitignore(content), "utf8");
2066
- return;
2067
- }
2068
- const confirmed = input.confirmGitignore ? await input.confirmGitignore() : false;
2069
- if (!confirmed) {
2070
- warn(
2071
- input.io,
2072
- `clio-coder context init: .gitignore does not ignore .clio-coder/; local context, skills, agents, and handoffs may leak into commits.
2073
- rerun with --yes to append '${CLIO_GITIGNORE_LINE}' to .gitignore without prompting, or add that line yourself.
2074
- `
2075
- );
2076
- return;
2077
- }
2078
- writeFileSync(gitignorePath, migrateClioGitignore(content), "utf8");
2079
- }
2080
- function serializeBootstrapOutput(output) {
2081
- return serializeClioMd({ ...output, fingerprint: null });
2082
- }
2083
- function writeClioMdFile(cwd, output) {
2084
- const clioMdPath = join4(cwd, "CLIO-CODER.md");
2085
- mkdirSync(dirname3(clioMdPath), { recursive: true });
2086
- const serialized = serializeBootstrapOutput(output);
2087
- const parsed = parseClioMd(serialized);
2088
- if (!parsed.ok) throw new Error(`bootstrap produced invalid CLIO-CODER.md: ${parsed.errors.join("; ")}`);
2089
- writeFileSync(clioMdPath, serialized, "utf8");
2090
- return clioMdPath;
2091
- }
2092
- function timestampForPath(now) {
2093
- return now.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
2094
- }
2095
- function writeClioMdProposal(cwd, now, output) {
2096
- const dir = join4(cwd, ".clio-coder", "proposals");
2097
- mkdirSync(dir, { recursive: true });
2098
- const proposalPath = join4(dir, `CLIO-CODER-${timestampForPath(now)}.md`);
2099
- writeFileSync(proposalPath, serializeBootstrapOutput(output), "utf8");
2100
- return proposalPath;
2101
- }
2102
- function boundedStateString(value, maxChars) {
2103
- if (value === void 0) return void 0;
2104
- const bounded = value.replace(/\s+/g, " ").trim().slice(0, maxChars);
2105
- return bounded.length > 0 ? bounded : void 0;
2106
- }
2107
- function safeStateCounter(value) {
2108
- return value !== void 0 && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
2109
- }
2110
- function durableGenerationTelemetry(telemetry) {
2111
- const state = {
2112
- mode: telemetry.mode,
2113
- parserOutcome: telemetry.parserOutcome
2114
- };
2115
- const fallbackReason = boundedStateString(telemetry.fallbackReason, 500);
2116
- if (fallbackReason) state.fallbackReason = fallbackReason;
2117
- const run = telemetry.run;
2118
- if (!run) return state;
2119
- state.structuredOutputMode = run.structuredOutputMode;
2120
- for (const [key, value] of [
2121
- ["runId", run.runId],
2122
- ["targetId", run.targetId],
2123
- ["wireModelId", run.wireModelId],
2124
- ["runtimeId", run.runtimeId],
2125
- ["runtimeKind", run.runtimeKind],
2126
- ["thinkingLevel", run.thinkingLevel]
2127
- ]) {
2128
- const bounded = boundedStateString(value, 512);
2129
- if (bounded) state[key] = bounded;
2130
- }
2131
- for (const [key, value] of [
2132
- ["tokenCount", run.tokens?.total],
2133
- ["toolCalls", run.toolCalls],
2134
- ["durationMs", run.durationMs],
2135
- ["promptBytes", run.promptBytes],
2136
- ["outputBytes", run.outputBytes]
2137
- ]) {
2138
- const counter = safeStateCounter(value);
2139
- if (counter !== void 0) state[key] = counter;
2140
- }
2141
- return state;
2142
- }
2143
- function writeProjectState(cwd, projectType, now, indexedAt, adoption, recordAdoption, codewikiVersion, fingerprint, generation, generated) {
2144
- const statePath2 = statePath(cwd);
2145
- const prev = readClioState(cwd);
2146
- const lastBootstrap = generated ? durableGenerationTelemetry(generation) : prev?.lastBootstrap ?? durableGenerationTelemetry(generation);
2147
- const contextSources = recordAdoption ? adoption.sourceSnapshots : prev?.contextSources;
2148
- const contextSourceHash = contextSources ? adoptionSnapshotsHash(contextSources) : void 0;
2149
- writeClioState(cwd, {
2150
- version: 1,
2151
- projectType,
2152
- fingerprint,
2153
- codewikiVersion,
2154
- lastInitAt: now.toISOString(),
2155
- lastSessionAt: now.toISOString(),
2156
- lastIndexedAt: indexedAt,
2157
- lastBootstrap,
2158
- ...contextSources ? { contextSources } : {},
2159
- ...contextSourceHash ? { contextSourceHash } : {}
2160
- });
2161
- return statePath2;
2162
- }
2163
- function persistCodewikiForGeneration(cwd, projectType, indexedAt, codewiki, fingerprint) {
2164
- const prev = readClioState(cwd);
2165
- writeClioState(cwd, {
2166
- version: 1,
2167
- projectType,
2168
- fingerprint,
2169
- codewikiVersion: codewiki.version,
2170
- ...prev?.contextSources ? { contextSources: prev.contextSources } : {},
2171
- ...prev?.contextSourceHash ? { contextSourceHash: prev.contextSourceHash } : {},
2172
- ...prev?.lastInitAt ? { lastInitAt: prev.lastInitAt } : {},
2173
- ...prev?.lastBootstrap ? { lastBootstrap: prev.lastBootstrap } : {},
2174
- lastSessionAt: prev?.lastSessionAt ?? indexedAt,
2175
- lastIndexedAt: indexedAt
2176
- });
2177
- }
2178
- function summarizeAdoption(adoption, mode) {
2179
- let projectSourceCount = 0;
2180
- let globalSourceCount = 0;
2181
- for (const source of adoption.sources) {
2182
- if (source.scope === "global") globalSourceCount += 1;
2183
- else projectSourceCount += 1;
2184
- }
2185
- return {
2186
- mode,
2187
- sourceCount: adoption.sources.length,
2188
- projectSourceCount,
2189
- globalSourceCount,
2190
- importedRuleCount: adoption.importedRules.length,
2191
- conflictCount: adoption.conflicts.length,
2192
- rejectedCount: adoption.rejected.length,
2193
- includeGlobal: adoption.includeGlobal
2194
- };
2195
- }
2196
- function codewikiEntryPoints(codewiki, limit = 6) {
2197
- const fileById = new Map(codewiki.files.map((file) => [file.id, file]));
2198
- const tagged = codewiki.files.filter((file) => file.lang !== "config" && file.role === "entry").map((file) => file.path).sort((a, b) => a.localeCompare(b));
2199
- if (tagged.length >= limit) return tagged.slice(0, limit);
2200
- const inDegree = /* @__PURE__ */ new Map();
2201
- for (const edge of codewiki.edges) {
2202
- if (!("toFileId" in edge)) continue;
2203
- inDegree.set(edge.toFileId, (inDegree.get(edge.toFileId) ?? 0) + 1);
2204
- }
2205
- const ranked = [...inDegree.entries()].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0])).map(([fileId]) => fileById.get(fileId)?.path).filter((path) => typeof path === "string").filter((path) => !tagged.includes(path));
2206
- return [...tagged, ...ranked].slice(0, limit);
2207
- }
2208
- async function runBootstrap(input = {}) {
2209
- const cwd = input.cwd ?? process.cwd();
2210
- const tomlFiles = createTomlFileReader(cwd);
2211
- const projectType = detectProjectType(cwd);
2212
- progress(input, {
2213
- phase: "scan",
2214
- status: "started",
2215
- message: "scanning project and sibling agent context",
2216
- detail: projectType
2217
- });
2218
- const adoption = scanAgentConfigs({
2219
- cwd,
2220
- ...input.homeDir ? { homeDir: input.homeDir } : {},
2221
- includeGlobal: input.includeGlobalImports === true
2222
- });
2223
- const siblingFiles = loadBootstrapSiblingFiles(adoption);
2224
- progress(input, {
2225
- phase: "scan",
2226
- status: "completed",
2227
- message: siblingFiles.length === 0 ? "no sibling context files found" : `folded ${siblingFiles.length} sibling context file${siblingFiles.length === 1 ? "" : "s"}`,
2228
- current: siblingFiles.length,
2229
- total: siblingFiles.length
2230
- });
2231
- const now = input.now?.() ?? /* @__PURE__ */ new Date();
2232
- const indexedAt = now.toISOString();
2233
- progress(input, { phase: "codewiki", status: "started", message: "building codewiki index" });
2234
- let codewiki;
2235
- let codewikiFingerprint;
2236
- if (input.preview === true) {
2237
- const candidate = await buildCodewikiCandidate(cwd, projectType);
2238
- codewiki = candidate.codewiki;
2239
- codewikiFingerprint = candidate.fingerprint;
2240
- } else {
2241
- const coordinated = await coordinateCodewikiWrite(cwd, () => ({ kind: "build", cwd, language: projectType }), {
2242
- beforeCommit: (_result, workspace) => ensureGitignore(workspace, input),
2243
- afterCommit: ({ codewiki: committed, fingerprint }, workspace) => persistCodewikiForGeneration(workspace, projectType, indexedAt, committed, fingerprint)
2244
- });
2245
- if (!coordinated) throw new Error("codewiki bootstrap transaction did not commit");
2246
- codewiki = coordinated.codewiki;
2247
- codewikiFingerprint = coordinated.worker.fingerprint;
2248
- }
2249
- const codewikiEntryCount = indexedSourceFileCount(codewiki);
2250
- progress(input, {
2251
- phase: "codewiki",
2252
- status: "completed",
2253
- message: `indexed ${codewikiEntryCount} source file${codewikiEntryCount === 1 ? "" : "s"}`,
2254
- current: codewikiEntryCount,
2255
- total: codewikiEntryCount
2256
- });
2257
- const hadClioMd = existsSync4(join4(cwd, "CLIO-CODER.md"));
2258
- const useExistingClioMdAsSource = hadClioMd && input.rewriteClioMd !== true;
2259
- const existingClioMdText = useExistingClioMdAsSource ? readExistingClioMdText(cwd) : null;
2260
- const existingClioMd = useExistingClioMdAsSource ? tryReadClioMd(cwd) : null;
2261
- const existingParsed = existingClioMd?.ok ? existingClioMd.value : void 0;
2262
- const replaceClioMd = input.applyClioMd === true || input.rewriteClioMd === true;
2263
- if (input.adopt === true && input.preview !== true && hadClioMd && !existingParsed && !replaceClioMd && input.proposeClioMd !== true) {
2264
- const detail = existingClioMd && !existingClioMd.ok ? ` (${existingClioMd.error})` : "";
2265
- throw new Error(
2266
- `cannot refresh Imported agent context because CLIO-CODER.md is malformed${detail}; use --apply or --rewrite after reviewing the handbook`
2267
- );
2268
- }
2269
- const shouldGenerate = !hadClioMd || replaceClioMd || input.proposeClioMd === true || input.generate !== void 0;
2270
- let output;
2271
- let generation = {
2272
- mode: shouldGenerate ? "heuristic" : existingParsed ? "existing" : "heuristic",
2273
- parserOutcome: "not-run"
2274
- };
2275
- let reportedGeneration;
2276
- const reportGeneration = (reported) => {
2277
- if (reportedGeneration === void 0) reportedGeneration = reported;
2278
- };
2279
- if (shouldGenerate) {
2280
- progress(input, {
2281
- phase: "generate",
2282
- status: "started",
2283
- message: input.generate ? "drafting CLIO-CODER.md with the bootstrap agent" : "drafting CLIO-CODER.md with heuristic"
2284
- });
2285
- output = await (input.generate ?? heuristicBootstrapOutput)({
2286
- cwd,
2287
- expectedProjectName: projectName(cwd, tomlFiles),
2288
- tomlFiles,
2289
- projectType,
2290
- siblingFiles,
2291
- adoption,
2292
- codewiki,
2293
- ...existingParsed ? { existingClioMd: existingParsed } : {},
2294
- ...existingClioMdText ? { existingClioMdText } : {},
2295
- ...input.onProgress ? { progress: input.onProgress } : {},
2296
- reportGeneration
2297
- });
2298
- generation = reportedGeneration ?? generation;
2299
- let retainedModelSections = 0;
2300
- output = stabilizeGeneratedOutput(
2301
- {
2302
- cwd,
2303
- expectedProjectName: projectName(cwd, tomlFiles),
2304
- tomlFiles,
2305
- projectType,
2306
- siblingFiles,
2307
- adoption,
2308
- codewiki,
2309
- ...existingParsed ? { existingClioMd: existingParsed } : {},
2310
- ...existingClioMdText ? { existingClioMdText } : {}
2311
- },
2312
- output,
2313
- () => {
2314
- retainedModelSections += 1;
2315
- },
2316
- generation.mode === "model"
2317
- );
2318
- if (generation.mode === "model" && retainedModelSections === 0) {
2319
- generation = {
2320
- ...generation,
2321
- mode: "heuristic",
2322
- fallbackReason: "Scout draft contributed no evidence-grounded custom sections"
2323
- };
2324
- }
2325
- progress(input, {
2326
- phase: "generate",
2327
- status: "completed",
2328
- message: `${output.projectName}: ${output.sections?.length ?? 0} custom section${(output.sections?.length ?? 0) === 1 ? "" : "s"}`,
2329
- detail: `${generation.mode}; parser=${generation.parserOutcome}`
2330
- });
2331
- } else {
2332
- output = existingParsed ? bootstrapOutputFromParsed(existingParsed) : await heuristicBootstrapOutput({ cwd, tomlFiles, projectType, siblingFiles, adoption, codewiki });
2333
- progress(input, {
2334
- phase: "generate",
2335
- status: "completed",
2336
- message: hadClioMd ? "preserving existing CLIO-CODER.md; no generated rewrite requested" : "using heuristic CLIO-CODER.md draft"
2337
- });
2338
- }
2339
- if (input.adopt === true) {
2340
- output = replaceImportedAgentContext(output, renderImportedAgentContext(adoption));
2341
- }
2342
- const readNames = siblingFiles.map((file) => file.path).sort((a, b) => a.localeCompare(b));
2343
- const previewStatus = gitStatus(cwd);
2344
- if (input.preview === true) {
2345
- progress(input, { phase: "clio-md", status: "completed", message: "preview ready; no files written" });
2346
- const summary2 = {
2347
- action: "previewed",
2348
- contextFileCount: readNames.length,
2349
- contextFileNames: readNames,
2350
- codewikiEntries: codewikiEntryCount,
2351
- dirtyFiles: countStatusLines(previewStatus),
2352
- adoption: summarizeAdoption(adoption, "preview")
2353
- };
2354
- out(input.io, formatBootstrapSummary(summary2));
2355
- return {
2356
- clioMdPath: join4(cwd, "CLIO-CODER.md"),
2357
- statePath: statePath(cwd),
2358
- siblingFiles,
2359
- output,
2360
- projectType,
2361
- summary: summary2,
2362
- adoption,
2363
- telemetry: { generation },
2364
- preload: measureProjectPreload(cwd)
2365
- };
2366
- }
2367
- let clioMdPath = join4(cwd, "CLIO-CODER.md");
2368
- let proposalPath;
2369
- let action = "preserved";
2370
- progress(input, {
2371
- phase: "clio-md",
2372
- status: "started",
2373
- message: hadClioMd ? "preserving CLIO-CODER.md" : "writing CLIO-CODER.md"
2374
- });
2375
- if (!hadClioMd) {
2376
- clioMdPath = writeClioMdFile(cwd, output);
2377
- action = "wrote";
2378
- } else if (replaceClioMd) {
2379
- clioMdPath = writeClioMdFile(cwd, output);
2380
- action = "refreshed";
2381
- } else if (input.adopt === true && existingParsed) {
2382
- clioMdPath = writeClioMdFile(cwd, output);
2383
- action = "refreshed";
2384
- } else if (input.proposeClioMd === true) {
2385
- proposalPath = writeClioMdProposal(cwd, now, output);
2386
- action = "proposed";
2387
- }
2388
- progress(input, {
2389
- phase: "clio-md",
2390
- status: "completed",
2391
- message: action === "wrote" ? "CLIO-CODER.md written" : action === "refreshed" ? "CLIO-CODER.md refreshed" : action === "proposed" ? "CLIO-CODER.md proposal written" : "CLIO-CODER.md preserved",
2392
- detail: proposalPath ?? clioMdPath
2393
- });
2394
- const adoptionApplied = input.adopt === true && (action === "wrote" || action === "refreshed");
2395
- progress(input, { phase: "state", status: "started", message: "persisting codewiki and project state" });
2396
- const statePath2 = writeProjectState(
2397
- cwd,
2398
- projectType,
2399
- now,
2400
- indexedAt,
2401
- adoption,
2402
- adoptionApplied,
2403
- codewiki.version,
2404
- codewikiFingerprint,
2405
- generation,
2406
- shouldGenerate
2407
- );
2408
- progress(input, {
2409
- phase: "state",
2410
- status: "completed",
2411
- message: `state updated; ${codewikiEntryCount} codewiki entr${codewikiEntryCount === 1 ? "y" : "ies"}`
2412
- });
2413
- const postStatus = gitStatus(cwd);
2414
- const summary = {
2415
- action,
2416
- contextFileCount: readNames.length,
2417
- contextFileNames: readNames,
2418
- codewikiEntries: codewikiEntryCount,
2419
- dirtyFiles: countStatusLines(postStatus),
2420
- adoption: summarizeAdoption(adoption, adoptionApplied ? "adopt" : "scan"),
2421
- ...proposalPath ? { proposalPath } : {}
2422
- };
2423
- out(input.io, formatBootstrapSummary(summary));
2424
- const preload = measureProjectPreload(cwd);
2425
- out(input.io, ` preload: ${preload.label}
2426
- `);
2427
- if (preload.mode === "full" && preload.nearLimit) {
2428
- warn(
2429
- input.io,
2430
- ` warning: project context is within 10% of the preload limit (${preload.chars} chars of 8000, ${preload.lines} lines of 220); the next growth may flip it to a synopsis
2431
- `
2432
- );
2433
- }
2434
- progress(input, {
2435
- phase: "done",
2436
- status: "completed",
2437
- message: `${summary.action} CLIO-CODER.md; ${summary.dirtyFiles} dirty file${summary.dirtyFiles === 1 ? "" : "s"}; preload: ${preload.label}`
2438
- });
2439
- return {
2440
- clioMdPath,
2441
- statePath: statePath2,
2442
- siblingFiles,
2443
- output,
2444
- projectType,
2445
- summary,
2446
- adoption,
2447
- telemetry: { generation },
2448
- preload
2449
- };
2450
- }
2451
-
2452
- // src/domains/context/clear.ts
2453
- init_esm_shims();
2454
- import { existsSync as existsSync5, rmSync } from "node:fs";
2455
- import { join as join5 } from "node:path";
2456
- var ACCUMULATED_CONTEXT_PATHS = [
2457
- ".clio-coder/codewiki.json",
2458
- ".clio-coder/state.json",
2459
- ".clio-coder/handoffs",
2460
- ".clio-coder/proposals"
2461
- ];
2462
- var PRESERVED_CONTEXT_PATHS = [
2463
- "CLIO-CODER.md",
2464
- "CLIO-CODER.override.md",
2465
- ".clio-coder/agents",
2466
- ".clio-coder/skills",
2467
- ".clio-coder/wiki"
2468
- ];
2469
- function out2(io, message) {
2470
- io?.stdout(message);
2471
- }
2472
- function relativeContextPath(cwd, relPath) {
2473
- return join5(cwd, ...relPath.split("/"));
2474
- }
2475
- function removeIfPresent(cwd, relPath, removed) {
2476
- const absPath = relativeContextPath(cwd, relPath);
2477
- if (!existsSync5(absPath)) return;
2478
- rmSync(absPath, { recursive: true, force: true });
2479
- removed.push(relPath);
2480
- }
2481
- async function runContextClear(input = {}) {
2482
- const cwd = input.cwd ?? process.cwd();
2483
- const confirmed = await input.confirmContext?.();
2484
- if (confirmed !== true) {
2485
- out2(input.io, "clio-coder context reset cancelled; no files removed.\n");
2486
- return { action: "cancelled", removed: [], preserved: [...PRESERVED_CONTEXT_PATHS] };
2487
- }
2488
- const { removed, preserved } = await coordinateCodewikiExclusive(cwd, async (workspace) => {
2489
- const removed2 = [];
2490
- for (const relPath of ACCUMULATED_CONTEXT_PATHS) removeIfPresent(workspace, relPath, removed2);
2491
- const preserved2 = [...PRESERVED_CONTEXT_PATHS];
2492
- if (input.all === true) {
2493
- const confirmedAll = await input.confirmAll?.();
2494
- if (confirmedAll === true) {
2495
- removeIfPresent(workspace, "CLIO-CODER.md", removed2);
2496
- const index = preserved2.indexOf("CLIO-CODER.md");
2497
- if (index !== -1) preserved2.splice(index, 1);
2498
- }
2499
- }
2500
- return { removed: removed2, preserved: preserved2 };
2501
- });
2502
- out2(
2503
- input.io,
2504
- [
2505
- `clio-coder context reset removed ${removed.length === 0 ? "nothing" : removed.join(", ")}`,
2506
- ` preserved ${preserved.join(", ")}`,
2507
- ""
2508
- ].join("\n")
2509
- );
2510
- return { action: "cleared", removed, preserved };
2511
- }
2512
-
2513
- // src/domains/context/operator-profile.ts
2514
- init_esm_shims();
2515
- var import_yaml2 = __toESM(require_dist(), 1);
2516
- import { createHash as createHash2 } from "node:crypto";
2517
- import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
2518
- import { join as join6 } from "node:path";
2519
- var RESPONSE_POSTURES = ["concise", "balanced", "thorough"];
2520
- var VALIDATION_PREFERENCES = ["tests-first", "manual", "trust"];
2521
- var COMMIT_MESSAGE_STYLES = ["conventional", "descriptive", "terse"];
2522
- var OPERATOR_PROFILE_MAX_CHARS = 700;
2523
- var OPERATOR_PROFILE_MAX_LOCAL_PATHS = 8;
2524
- function isRecord2(value) {
2525
- return value !== null && typeof value === "object" && !Array.isArray(value);
2526
- }
2527
- function readEnum(value, allowed, field, issues) {
2528
- if (value === void 0) return void 0;
2529
- if (typeof value === "string" && allowed.includes(value)) return value;
2530
- issues.push(`${field} must be one of ${allowed.join(", ")}`);
2531
- return void 0;
2532
- }
2533
- function readProfileBlob(value, issues) {
2534
- if (!isRecord2(value)) {
2535
- if (value !== null && value !== void 0) issues.push("profile must be a mapping at the root");
2536
- return {};
2537
- }
2538
- const profile = {};
2539
- const posture = readEnum(value.responsePosture, RESPONSE_POSTURES, "responsePosture", issues);
2540
- if (posture) profile.responsePosture = posture;
2541
- const validation = readEnum(value.validationPreference, VALIDATION_PREFERENCES, "validationPreference", issues);
2542
- if (validation) profile.validationPreference = validation;
2543
- const commit = readEnum(value.commitMessageStyle, COMMIT_MESSAGE_STYLES, "commitMessageStyle", issues);
2544
- if (commit) profile.commitMessageStyle = commit;
2545
- if (value.localOnlyPaths !== void 0) {
2546
- if (Array.isArray(value.localOnlyPaths)) {
2547
- const paths = value.localOnlyPaths.filter((item) => typeof item === "string" && item.length > 0);
2548
- if (paths.length > 0) profile.localOnlyPaths = paths.slice(0, OPERATOR_PROFILE_MAX_LOCAL_PATHS);
2549
- } else {
2550
- issues.push("localOnlyPaths must be an array of strings");
2551
- }
2552
- }
2553
- return profile;
2554
- }
2555
- function readProfileFile(path, issues) {
2556
- if (!existsSync6(path)) return { profile: {}, present: false };
2557
- try {
2558
- return { profile: readProfileBlob((0, import_yaml2.parse)(readFileSync5(path, "utf8")), issues), present: true };
2559
- } catch (err) {
2560
- issues.push(`${path}: invalid YAML: ${err instanceof Error ? err.message : String(err)}`);
2561
- return { profile: {}, present: false };
2562
- }
2563
- }
2564
- function loadOperatorProfile(cwd, options = {}) {
2565
- const issues = [];
2566
- const userPath = options.userPath ?? join6(resolveClioDirs().config, "profile.yaml");
2567
- const projectPath = join6(cwd, ".clio-coder", "profile.yaml");
2568
- const user = readProfileFile(userPath, issues);
2569
- const project = readProfileFile(projectPath, issues);
2570
- const profile = { ...user.profile, ...project.profile };
2571
- let origin = "none";
2572
- let sourcePath;
2573
- if (project.present) {
2574
- origin = "project";
2575
- sourcePath = projectPath;
2576
- } else if (user.present) {
2577
- origin = "user";
2578
- sourcePath = userPath;
2579
- }
2580
- const result = { profile, origin, issues };
2581
- if (sourcePath !== void 0) {
2582
- result.sourcePath = sourcePath;
2583
- result.hash = createHash2("sha256").update(JSON.stringify(profile)).digest("hex").slice(0, 16);
2584
- }
2585
- return result;
2586
- }
2587
- function renderOperatorProfile(profile) {
2588
- const lines = [];
2589
- if (profile.responsePosture) lines.push(`- Response posture: ${profile.responsePosture}.`);
2590
- if (profile.validationPreference) lines.push(`- Validation preference: ${profile.validationPreference}.`);
2591
- if (profile.commitMessageStyle) lines.push(`- Commit-message style: ${profile.commitMessageStyle}.`);
2592
- if (profile.localOnlyPaths && profile.localOnlyPaths.length > 0) {
2593
- lines.push(`- Keep local-only (do not push or share): ${profile.localOnlyPaths.join(", ")}.`);
2594
- }
2595
- if (lines.length === 0) return { text: "", tokenEstimate: 0 };
2596
- const full = `## Operator profile
2597
- ${lines.join("\n")}`;
2598
- const text = full.length > OPERATOR_PROFILE_MAX_CHARS ? `${full.slice(0, OPERATOR_PROFILE_MAX_CHARS - 1)}\u2026` : full;
2599
- return { text, tokenEstimate: ceilChars(text.length) };
2600
- }
2601
-
2602
- // src/domains/context/project-rules.ts
2603
- init_esm_shims();
2604
- var import_yaml3 = __toESM(require_dist(), 1);
2605
- import { createHash as createHash3 } from "node:crypto";
2606
- import { readdirSync as readdirSync3, readFileSync as readFileSync6 } from "node:fs";
2607
- import { join as join7, relative as relative2, sep as sep2 } from "node:path";
2608
- var FRONTMATTER_RE = /^---\n([\s\S]*?)\n---\n?/;
2609
- function isRecord3(value) {
2610
- return value !== null && typeof value === "object" && !Array.isArray(value);
2611
- }
2612
- function readStringArray(value) {
2613
- if (!Array.isArray(value)) return void 0;
2614
- const out3 = [];
2615
- for (const item of value) {
2616
- if (typeof item === "string" && item.length > 0) out3.push(item);
2617
- }
2618
- return out3.length > 0 ? out3 : void 0;
2619
- }
2620
- function validateGlobArray(value, field, id, issues) {
2621
- const parsed = readStringArray(value);
2622
- if (parsed === void 0) {
2623
- issues.push(`${id}: frontmatter ${field} must be a non-empty string array`);
2624
- return void 0;
2625
- }
2626
- for (const pattern of parsed) {
2627
- try {
2628
- compileGlobRegex(pattern);
2629
- } catch (err) {
2630
- issues.push(
2631
- `${id}: invalid ${field} glob ${JSON.stringify(pattern)}: ${err instanceof Error ? err.message : String(err)}`
2632
- );
2633
- return void 0;
2634
- }
2635
- }
2636
- return parsed;
2637
- }
2638
- function walkMarkdown(dir, root, out3) {
2639
- let entries;
2640
- try {
2641
- entries = readdirSync3(dir, { withFileTypes: true });
2642
- } catch {
2643
- return;
2644
- }
2645
- for (const entry of entries) {
2646
- const full = join7(dir, entry.name);
2647
- if (entry.isDirectory()) walkMarkdown(full, root, out3);
2648
- else if (entry.isFile() && entry.name.endsWith(".md")) out3.push(full);
2649
- }
2650
- }
2651
- function parseRule(filePath, root, issues) {
2652
- let text;
2653
- try {
2654
- text = readFileSync6(filePath, "utf8").replace(/\r\n/g, "\n");
2655
- } catch (err) {
2656
- issues.push(`${filePath}: ${err instanceof Error ? err.message : String(err)}`);
2657
- return { excludes: [] };
2658
- }
2659
- const id = relative2(root, filePath).split(sep2).join("/");
2660
- let body = text;
2661
- let paths;
2662
- let excludes = [];
2663
- let enabled = true;
2664
- let description2;
2665
- let invalidFrontmatter = false;
2666
- const match = FRONTMATTER_RE.exec(text);
2667
- if (match) {
2668
- body = text.slice(match[0].length);
2669
- try {
2670
- const front = (0, import_yaml3.parse)(match[1] ?? "");
2671
- if (isRecord3(front)) {
2672
- if (Object.hasOwn(front, "paths")) {
2673
- const parsedPaths = validateGlobArray(front.paths, "paths", id, issues);
2674
- if (parsedPaths === void 0) invalidFrontmatter = true;
2675
- else paths = parsedPaths;
2676
- }
2677
- if (Object.hasOwn(front, "excludes")) {
2678
- const parsedExcludes = validateGlobArray(front.excludes, "excludes", id, issues);
2679
- if (parsedExcludes === void 0) invalidFrontmatter = true;
2680
- else excludes = parsedExcludes;
2681
- }
2682
- if (Object.hasOwn(front, "enabled")) {
2683
- if (typeof front.enabled === "boolean") enabled = front.enabled;
2684
- else {
2685
- issues.push(`${id}: frontmatter enabled must be a boolean`);
2686
- invalidFrontmatter = true;
2687
- }
2688
- }
2689
- if (Object.hasOwn(front, "description")) {
2690
- if (typeof front.description === "string") description2 = front.description;
2691
- else {
2692
- issues.push(`${id}: frontmatter description must be a string`);
2693
- invalidFrontmatter = true;
2694
- }
2695
- }
2696
- } else if (front !== null && front !== void 0) {
2697
- issues.push(`${id}: frontmatter must be a mapping`);
2698
- invalidFrontmatter = true;
2699
- }
2700
- } catch (err) {
2701
- issues.push(`${id}: invalid frontmatter: ${err instanceof Error ? err.message : String(err)}`);
2702
- invalidFrontmatter = true;
2703
- }
2704
- } else if (text.startsWith("---\n")) {
2705
- issues.push(`${id}: invalid frontmatter: missing closing marker`);
2706
- invalidFrontmatter = true;
2707
- }
2708
- if (invalidFrontmatter) return { excludes: [] };
2709
- const trimmedBody = body.trim();
2710
- const hash = createHash3("sha256").update(trimmedBody).digest("hex").slice(0, 16);
2711
- const rule = {
2712
- id,
2713
- sourcePath: join7(".clio-coder", "rules", id),
2714
- hash,
2715
- tokenEstimate: ceilChars(trimmedBody.length),
2716
- enabled,
2717
- body: trimmedBody
2718
- };
2719
- if (paths !== void 0) rule.paths = paths;
2720
- if (description2 !== void 0) rule.description = description2;
2721
- return { rule, excludes };
2722
- }
2723
- function loadProjectRules(cwd) {
2724
- const root = join7(cwd, ".clio-coder", "rules");
2725
- const issues = [];
2726
- const files = [];
2727
- walkMarkdown(root, root, files);
2728
- files.sort();
2729
- const rules = [];
2730
- const excludeSet = /* @__PURE__ */ new Set();
2731
- for (const file of files) {
2732
- const parsed = parseRule(file, root, issues);
2733
- if (parsed.rule) rules.push(parsed.rule);
2734
- for (const glob of parsed.excludes) excludeSet.add(glob);
2735
- }
2736
- rules.sort((a, b) => a.id.localeCompare(b.id));
2737
- return { rules, excludes: [...excludeSet], issues };
2738
- }
2739
- function ruleMatchesAnyPath(rule, workingPaths) {
2740
- for (const pattern of rule.paths ?? []) {
2741
- let regex;
2742
- try {
2743
- regex = compileGlobRegex(pattern);
2744
- } catch {
2745
- continue;
2746
- }
2747
- for (const path of workingPaths) {
2748
- const normalized = normalizeGlobInput(path);
2749
- if (regex.test(normalized)) return true;
2750
- if (normalized.endsWith("/") && globMatchesInsideDirectory(regex, pattern, normalized)) return true;
2751
- }
2752
- }
2753
- return false;
2754
- }
2755
- function materializedGlobVariants(pattern) {
2756
- let variants = [""];
2757
- const normalized = normalizeGlobInput(pattern);
2758
- for (let index = 0; index < normalized.length; index += 1) {
2759
- const character = normalized[index];
2760
- if (character === void 0) break;
2761
- if (character === "*" && normalized[index + 1] === "*" && normalized[index + 2] === "/") {
2762
- variants = variants.flatMap((prefix) => [prefix, `${prefix}x/`]).slice(0, 64);
2763
- index += 2;
2764
- continue;
2765
- }
2766
- if (character === "*" && normalized[index + 1] === "*") {
2767
- variants = variants.map((prefix) => `${prefix}x`);
2768
- index += 1;
2769
- continue;
2770
- }
2771
- if (character === "*" || character === "?") {
2772
- variants = variants.map((prefix) => `${prefix}x`);
2773
- continue;
2774
- }
2775
- if (character === "[") {
2776
- const end = normalized.indexOf("]", index + 1);
2777
- const selected = end === -1 ? "x" : normalized[index + 1] ?? "x";
2778
- variants = variants.map((prefix) => `${prefix}${selected}`);
2779
- index = end === -1 ? index : end;
2780
- continue;
2781
- }
2782
- variants = variants.map((prefix) => `${prefix}${character}`);
2783
- }
2784
- return variants;
2785
- }
2786
- function globMatchesInsideDirectory(regex, pattern, directory) {
2787
- const candidates = /* @__PURE__ */ new Set([`${directory}x`, `${directory}x/x`]);
2788
- for (const materialized of materializedGlobVariants(pattern)) {
2789
- if (materialized.startsWith(directory)) candidates.add(materialized);
2790
- const segments = materialized.split("/");
2791
- for (let index = 0; index < segments.length; index += 1) {
2792
- const suffix = segments.slice(index).join("/");
2793
- if (suffix.length > 0) candidates.add(`${directory}${suffix}`);
2794
- }
2795
- for (let index = 0; index < materialized.length; index += 1) {
2796
- candidates.add(`${directory}${materialized.slice(index)}`);
2797
- }
2798
- }
2799
- return [...candidates].some((candidate) => regex.test(candidate));
2800
- }
2801
- function selectActiveRules(rules, workingContextPaths) {
2802
- return rules.filter((rule) => {
2803
- if (!rule.enabled) return false;
2804
- if (rule.paths === void 0) return true;
2805
- return ruleMatchesAnyPath(rule, workingContextPaths);
2806
- });
2807
- }
2808
-
2809
- // src/domains/context/refresh.ts
2810
- init_esm_shims();
2811
- import { writeFileSync as writeFileSync3 } from "node:fs";
2812
- import { join as join10 } from "node:path";
2813
-
2814
- // src/domains/context/wiki/generate.ts
2815
- init_esm_shims();
2816
- import {
2817
- closeSync,
2818
- copyFileSync,
2819
- existsSync as existsSync7,
2820
- mkdirSync as mkdirSync3,
2821
- mkdtempSync,
2822
- openSync,
2823
- readdirSync as readdirSync4,
2824
- readFileSync as readFileSync8,
2825
- renameSync,
2826
- rmSync as rmSync3,
2827
- statSync as statSync3,
2828
- writeSync
2829
- } from "node:fs";
2830
- import { dirname as dirname5, join as join9 } from "node:path";
2831
-
2832
- // src/domains/context/wiki/assemble.ts
2833
- init_esm_shims();
2834
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync7, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
2835
- import { basename as basename3, dirname as dirname4, join as join8, normalize, posix, relative as relative3 } from "node:path";
2836
- var SOURCE_CITATION = /`((?:src|tests?|scripts|benchmarks|docs|packages|apps|lib|config|\.github)\/[^`\s:#]+)(?::(\d+)(?:-\d+)?)?(?::[A-Za-z_$][\w$.-]*)?`/g;
2837
- var INTERNAL_LINK = /\[[^\]]*\]\((?![a-z][a-z\d+.-]*:|\/\/|#)([^)\s]+\.md)(?:#[^)\s]*)?\)/gi;
2838
- var REPAIR_NOTE = /^<!-- (?:clio-coder|clio):wiki .*-->$/gm;
2839
- function readText2(filePath) {
2840
- try {
2841
- return readFileSync7(filePath, "utf8");
2842
- } catch {
2843
- return "";
2844
- }
2845
- }
2846
- function writeText(filePath, text) {
2847
- mkdirSync2(dirname4(filePath), { recursive: true });
2848
- writeFileSync2(filePath, text, "utf8");
2849
- }
2850
- function stripRepairNotes(body) {
2851
- return body.replace(REPAIR_NOTE, "").replace(/\n{3,}/g, "\n\n");
2852
- }
2853
- function renderRepairNote(issues) {
2854
- const links = issues.filter((issue) => issue.kind === "link").map((issue) => issue.reference);
2855
- const citations = issues.filter((issue) => issue.kind === "citation").map((issue) => issue.reference);
2856
- const parts = [];
2857
- if (links.length > 0) parts.push(`unresolved links: ${[...new Set(links)].join(", ")}`);
2858
- if (citations.length > 0) parts.push(`unresolved sources: ${[...new Set(citations)].join(", ")}`);
2859
- return parts.length === 0 ? "" : `
2860
- <!-- clio-coder:wiki ${parts.join("; ")} -->
2861
- `;
2862
- }
2863
- function repairPage(dir, sourceRoot, relPath, knownPages) {
2864
- const filePath = join8(dir, relPath);
2865
- const original = readText2(filePath);
2866
- const parsed = readWikiPage({ pagePath: relPath, content: original, sourceRoot });
2867
- const body = stripRepairNotes(parsed.body);
2868
- if (body.replace(/^#.*$/gm, "").trim().length === 0) {
2869
- return { metadata: parsed.metadata, changed: false, issues: [], empty: true };
2870
- }
2871
- const issues = [];
2872
- for (const cited of parsed.unresolvedPaths) {
2873
- issues.push({ page: relPath, kind: "citation", reference: cited });
2874
- }
2875
- for (const match of body.matchAll(SOURCE_CITATION)) {
2876
- const cited = match[1] ?? "";
2877
- if (resolveSourcePath(sourceRoot, cited) === null) {
2878
- issues.push({ page: relPath, kind: "citation", reference: cited });
2879
- }
2880
- }
2881
- for (const match of body.matchAll(INTERNAL_LINK)) {
2882
- const href = match[1] ?? "";
2883
- const target = posix.normalize(posix.join(posix.dirname(relPath), href));
2884
- if (target.startsWith("..") || !knownPages.has(target)) {
2885
- issues.push({ page: relPath, kind: "link", reference: href });
2886
- }
2887
- }
2888
- const rebuilt = `${renderWikiPage(parsed.metadata, body).trimEnd()}
2889
- ${renderRepairNote(issues)}`;
2890
- if (rebuilt !== original) writeText(filePath, rebuilt);
2891
- return { metadata: parsed.metadata, changed: rebuilt !== original, issues, empty: false };
2892
- }
2893
- function linkTo(fromDir, target) {
2894
- const href = posix.relative(fromDir === "." ? "" : fromDir, target);
2895
- return href.length > 0 ? href : posix.basename(target);
2896
- }
2897
- function escapeCell(value) {
2898
- return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
2899
- }
2900
- function codeList(values, limit) {
2901
- if (values.length === 0) return "\u2014";
2902
- const shown = values.slice(0, limit).map((value) => `\`${escapeCell(value)}\``);
2903
- return values.length > limit ? `${shown.join(", ")}, \u2026` : shown.join(", ");
2904
- }
2905
- function renderQuickstart(sourceRoot, plan, pages) {
2906
- const content = pages.filter((page) => page.path !== WIKI_QUICKSTART);
2907
- const lines = [`# ${basename3(sourceRoot)} wiki`, ""];
2908
- if (plan.overview.trim().length > 0) lines.push(plan.overview.trim(), "");
2909
- lines.push(
2910
- `This wiki is generated by \`clio-coder context wiki\` from ${content.length} page${content.length === 1 ? "" : "s"}. Each page opens with front matter naming the sources, symbols, and tests it documents.`,
2911
- "",
2912
- "## Pages",
2913
- ""
2914
- );
2915
- let currentSection = null;
2916
- for (const page of content) {
2917
- const section = posix.dirname(page.path);
2918
- if (section !== "." && section !== currentSection) {
2919
- lines.push(`- **${section}/**`);
2920
- currentSection = section;
2921
- }
2922
- const indent = section === "." ? "" : " ";
2923
- const summary = page.metadata.summary.length > 0 ? ` \u2014 ${page.metadata.summary}` : "";
2924
- lines.push(`${indent}- [${page.metadata.title}](${page.path})${summary}`);
2925
- }
2926
- const routable = content.filter(
2927
- (page) => page.metadata.sources.length > 0 || page.metadata.symbols.length > 0 || page.metadata.tests.length > 0
2928
- );
2929
- if (routable.length > 0) {
2930
- lines.push(
2931
- "",
2932
- "## Task routing",
2933
- "",
2934
- "| Area | Page | Sources | Symbols | Tests | Validate |",
2935
- "| --- | --- | --- | --- | --- | --- |"
2936
- );
2937
- for (const page of routable) {
2938
- lines.push(
2939
- `| ${escapeCell(page.metadata.title)} | [${escapeCell(page.metadata.title)}](${page.path}) | ${codeList(page.metadata.sources, 3)} | ${codeList(page.metadata.symbols, 3)} | ${codeList(page.metadata.tests, 2)} | ${codeList(page.metadata.validate, 1)} |`
2940
- );
2941
- }
2942
- }
2943
- return `${lines.join("\n")}
2944
- `;
2945
- }
2946
- function renderIndex(dir, pages, sections) {
2947
- const title = dir === "." ? "Wiki" : dir.split("/").join(" / ");
2948
- const lines = [`# ${title}`, ""];
2949
- if (pages.length > 0) {
2950
- for (const page of pages) {
2951
- const summary = page.metadata.summary.length > 0 ? ` \u2014 ${page.metadata.summary}` : "";
2952
- lines.push(`- [${page.metadata.title}](${linkTo(dir, page.path)})${summary}`);
2953
- }
2954
- lines.push("");
2955
- }
2956
- if (sections.length > 0) {
2957
- lines.push("## Sections", "");
2958
- for (const section of sections)
2959
- lines.push(`- [${posix.basename(section)}/](${linkTo(dir, `${section}/${WIKI_INDEX}`)})`);
2960
- lines.push("");
2961
- }
2962
- return `${lines.join("\n").trimEnd()}
2963
- `;
2964
- }
2965
- function assembleWikiTree(input) {
2966
- const { dir, sourceRoot } = input;
2967
- const authored = wikiMarkdownFilesInDir(dir).filter((relPath) => !isGeneratedWikiFile(relPath));
2968
- const knownPages = /* @__PURE__ */ new Set([...authored, WIKI_QUICKSTART]);
2969
- const assembled = [];
2970
- const issues = [];
2971
- const dropped = [];
2972
- let repaired = 0;
2973
- for (const relPath of authored) {
2974
- const result = repairPage(dir, sourceRoot, relPath, knownPages);
2975
- if (result.empty) {
2976
- rmSync2(join8(dir, relPath), { force: true });
2977
- dropped.push(relPath);
2978
- continue;
2979
- }
2980
- if (result.changed) repaired += 1;
2981
- issues.push(...result.issues);
2982
- assembled.push({ path: relPath, metadata: result.metadata });
2983
- }
2984
- writeText(join8(dir, WIKI_QUICKSTART), renderQuickstart(sourceRoot, input.plan, assembled));
2985
- const directories = /* @__PURE__ */ new Set(["."]);
2986
- for (const page of assembled) {
2987
- let section = posix.dirname(page.path);
2988
- while (section !== "." && section.length > 0) {
2989
- directories.add(section);
2990
- section = posix.dirname(section);
2991
- }
2992
- }
2993
- for (const directory of directories) {
2994
- const pagesHere = assembled.filter((page) => posix.dirname(page.path) === directory);
2995
- const sectionsHere = [...directories].filter((candidate) => candidate !== "." && posix.dirname(candidate) === directory).sort();
2996
- const indexPath = directory === "." ? WIKI_INDEX : `${directory}/${WIKI_INDEX}`;
2997
- writeText(join8(dir, indexPath), renderIndex(directory, pagesHere, sectionsHere));
2998
- }
2999
- for (const relPath of wikiMarkdownFilesInDir(dir)) {
3000
- if (!isGeneratedWikiFile(relPath) || relPath === WIKI_QUICKSTART) continue;
3001
- const directory = posix.dirname(relPath);
3002
- if (!directories.has(directory)) rmSync2(join8(dir, relPath), { force: true });
3003
- }
3004
- return { pages: listWikiPagesInDir(dir), repaired, dropped, issues };
3005
- }
3006
- function pageSourceIndex(dir, sourceRoot) {
3007
- const index = /* @__PURE__ */ new Map();
3008
- for (const relPath of wikiMarkdownFilesInDir(dir)) {
3009
- if (isGeneratedWikiFile(relPath)) continue;
3010
- const { metadata } = readWikiPage({ pagePath: relPath, content: readText2(join8(dir, relPath)), sourceRoot });
3011
- index.set(relPath, [...metadata.sources, ...metadata.tests]);
3012
- }
3013
- return index;
3014
- }
3015
- function normalizeRepoPath(sourceRoot, candidate) {
3016
- const resolved = normalize(join8(sourceRoot, candidate));
3017
- const rel = relative3(sourceRoot, resolved);
3018
- return rel.split("\\").join("/");
3019
- }
3020
-
3021
- // src/domains/context/wiki/generate.ts
3022
- function progress2(input, event) {
3023
- input.onProgress?.(event);
3024
- }
3025
- function indexedSourceFileCount2(codewiki) {
3026
- return codewiki.files.filter((file) => file.lang !== "config").length;
3027
- }
3028
- async function loadOrBuildCodewiki(cwd) {
3029
- const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
3030
- const projectType = detectProjectType(cwd);
3031
- const coordinated = await coordinateCodewikiWrite(
3032
- cwd,
3033
- (current, workspace) => ({
3034
- kind: "ensure",
3035
- cwd: workspace,
3036
- language: projectType,
3037
- current,
3038
- previous: readClioState(workspace)?.fingerprint ?? null
3039
- }),
3040
- {
3041
- afterCommit: ({ codewiki, fingerprint, changed }, workspace) => {
3042
- const prev = readClioState(workspace);
3043
- if (!changed && prev) return;
3044
- writeClioState(workspace, {
3045
- version: 1,
3046
- projectType: prev?.projectType ?? projectType,
3047
- fingerprint,
3048
- codewikiVersion: codewiki.version,
3049
- ...prev?.contextSources ? { contextSources: prev.contextSources } : {},
3050
- ...prev?.contextSourceHash ? { contextSourceHash: prev.contextSourceHash } : {},
3051
- ...prev?.lastBootstrap ? { lastBootstrap: prev.lastBootstrap } : {},
3052
- ...prev?.lastInitAt ? { lastInitAt: prev.lastInitAt } : {},
3053
- lastSessionAt: prev?.lastSessionAt ?? generatedAt,
3054
- lastIndexedAt: generatedAt
3055
- });
3056
- }
3057
- }
3058
- );
3059
- if (!coordinated) throw new Error("codewiki wiki transaction did not commit");
3060
- return { codewiki: coordinated.codewiki, fingerprint: coordinated.worker.fingerprint };
3061
- }
3062
- function failed(problems, pages) {
3063
- return { status: "failed", pages, problems };
3064
- }
3065
- var STAGING_PREFIX = "wiki-staging-";
3066
- var WIKI_PREV_DIR = "wiki-prev";
3067
- var WIKI_LOCK_FILE = "wiki.lock";
3068
- function clioDir(cwd) {
3069
- return join9(cwd, ".clio-coder");
3070
- }
3071
- function isProcessAlive(pid) {
3072
- try {
3073
- process.kill(pid, 0);
3074
- return true;
3075
- } catch (err) {
3076
- return err.code === "EPERM";
3077
- }
3078
- }
3079
- function readLockPid(lockPath) {
3080
- try {
3081
- const parsed = Number.parseInt(readFileSync8(lockPath, "utf8").trim(), 10);
3082
- return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
3083
- } catch {
3084
- return null;
3085
- }
3086
- }
3087
- function acquireWikiLock(cwd) {
3088
- const dir = clioDir(cwd);
3089
- mkdirSync3(dir, { recursive: true });
3090
- const lockPath = join9(dir, WIKI_LOCK_FILE);
3091
- const release = () => {
3092
- try {
3093
- rmSync3(lockPath, { force: true });
3094
- } catch {
3095
- }
3096
- };
3097
- const create = () => {
3098
- const fd = openSync(lockPath, "wx");
3099
- try {
3100
- writeSync(fd, String(process.pid));
3101
- } finally {
3102
- closeSync(fd);
3103
- }
3104
- };
3105
- try {
3106
- create();
3107
- return { ok: true, release };
3108
- } catch (err) {
3109
- if (err.code !== "EEXIST") throw err;
3110
- }
3111
- const holder = readLockPid(lockPath);
3112
- if (holder !== null && isProcessAlive(holder)) {
3113
- return {
3114
- ok: false,
3115
- problem: `wiki generation is already running (lock held by pid ${holder} at ${lockPath})`
3116
- };
3117
- }
3118
- try {
3119
- rmSync3(lockPath, { force: true });
3120
- create();
3121
- return { ok: true, release };
3122
- } catch (err) {
3123
- if (err.code !== "EEXIST") throw err;
3124
- const racer = readLockPid(lockPath);
3125
- return {
3126
- ok: false,
3127
- problem: `wiki generation is already running (lock held by pid ${racer ?? "unknown"} at ${lockPath})`
3128
- };
3129
- }
3130
- }
3131
- function removeDir(dir) {
3132
- try {
3133
- rmSync3(dir, { recursive: true, force: true });
3134
- } catch {
3135
- }
3136
- }
3137
- function seedStaging(cwd, stagingDir) {
3138
- const source = wikiDir(cwd);
3139
- for (const relPath of wikiMarkdownFilesInDir(source)) {
3140
- const target = join9(stagingDir, relPath);
3141
- mkdirSync3(dirname5(target), { recursive: true });
3142
- try {
3143
- copyFileSync(join9(source, relPath), target);
3144
- } catch {
3145
- }
3146
- }
3147
- }
3148
- function adoptOrCreateStaging(cwd) {
3149
- const dir = clioDir(cwd);
3150
- mkdirSync3(dir, { recursive: true });
3151
- let entries;
3152
- try {
3153
- entries = readdirSync4(dir, { withFileTypes: true });
3154
- } catch {
3155
- entries = [];
3156
- }
3157
- const candidates = entries.filter((entry) => entry.isDirectory() && entry.name.startsWith(STAGING_PREFIX)).map((entry) => join9(dir, entry.name)).sort((a, b) => {
3158
- const at = statSync3(a).mtimeMs;
3159
- const bt = statSync3(b).mtimeMs;
3160
- return bt - at;
3161
- });
3162
- const resumable = candidates.find((candidate) => existsSync7(join9(candidate, WIKI_PLAN_FILE)));
3163
- for (const candidate of candidates) {
3164
- if (candidate !== resumable) removeDir(candidate);
3165
- }
3166
- if (resumable !== void 0) return { dir: resumable, adopted: true };
3167
- const fresh = mkdtempSync(join9(dir, STAGING_PREFIX));
3168
- seedStaging(cwd, fresh);
3169
- return { dir: fresh, adopted: false };
3170
- }
3171
- function promoteStaging(cwd, stagingDir, writeMeta) {
3172
- const wiki = wikiDir(cwd);
3173
- const prev = join9(clioDir(cwd), WIKI_PREV_DIR);
3174
- removeDir(prev);
3175
- const hadWiki = existsSync7(wiki);
3176
- if (hadWiki) renameSync(wiki, prev);
3177
- try {
3178
- renameSync(stagingDir, wiki);
3179
- writeMeta();
3180
- } catch (err) {
3181
- const problems = [`wiki promotion failed: ${err instanceof Error ? err.message : String(err)}`];
3182
- removeDir(stagingDir);
3183
- if (hadWiki) {
3184
- removeDir(wiki);
3185
- try {
3186
- renameSync(prev, wiki);
3187
- } catch {
3188
- problems.push(`previous wiki could not be restored and remains at ${prev}`);
3189
- return { ok: false, problems };
3190
- }
3191
- }
3192
- return { ok: false, problems };
3193
- }
3194
- if (hadWiki) removeDir(prev);
3195
- return { ok: true };
3196
- }
3197
- function resolvePlan(input) {
3198
- const staged = input.adopted ? readWikiPlanFile(input.stagingDir) : null;
3199
- if (staged !== null) return { plan: staged, resumed: true, unclaimedAreas: [] };
3200
- if (input.mode === "update" && input.previousPlan !== void 0) {
3201
- const pageSources = pageSourceIndex(input.stagingDir, input.cwd);
3202
- const changed = new Set(
3203
- changedPathsSince(input.cwd, input.gitHead).map((path) => normalizeRepoPath(input.cwd, path))
3204
- );
3205
- return {
3206
- plan: scopePlanForUpdate({
3207
- plan: input.previousPlan,
3208
- changedPaths: changed,
3209
- existingPages: new Set(wikiMarkdownFilesInDir(input.stagingDir)),
3210
- pageSources
3211
- }),
3212
- resumed: false,
3213
- unclaimedAreas: unclaimedCandidates(input.previousPlan, input.candidate, pageSources)
3214
- };
3215
- }
3216
- return { plan: input.candidate, resumed: false, unclaimedAreas: [] };
3217
- }
3218
- function reconcilePlan(plan, stagingDir) {
3219
- const contentFiles = wikiMarkdownFilesInDir(stagingDir).filter((relPath) => !isGeneratedWikiFile(relPath));
3220
- const onDisk = new Set(contentFiles);
3221
- const planned = new Set(plan.pages.map((page) => page.path));
3222
- const adopted = contentFiles.filter((relPath) => !planned.has(relPath)).map((relPath) => ({
3223
- path: relPath,
3224
- title: relPath.replace(/\.md$/, ""),
3225
- intent: "",
3226
- sources: [],
3227
- status: "written",
3228
- attempts: 1
3229
- }));
3230
- return {
3231
- ...plan,
3232
- pages: [
3233
- ...plan.pages.map(
3234
- (page) => onDisk.has(page.path) ? { ...page, status: "written" } : { ...page, status: "pending" }
3235
- ),
3236
- ...adopted
3237
- ]
3238
- };
3239
- }
3240
- async function runWikiGenerate(input = { model: "configured-clio-target" }) {
3241
- const cwd = input.cwd ?? process.cwd();
3242
- const existingMeta = readWikiMeta(cwd);
3243
- const mode = input.mode ?? (existingMeta ? "update" : "init");
3244
- const lock = acquireWikiLock(cwd);
3245
- if (!lock.ok) {
3246
- progress2(input, { phase: "generate", status: "failed", message: lock.problem });
3247
- progress2(input, { phase: "done", status: "failed", message: "wiki generation failed", detail: lock.problem });
3248
- return failed([lock.problem], listWikiPagesInDir(wikiDir(cwd)).length);
3249
- }
3250
- try {
3251
- progress2(input, { phase: "codewiki", status: "started", message: "loading codewiki for wiki generation" });
3252
- const { codewiki, fingerprint } = await loadOrBuildCodewiki(cwd);
3253
- const sourceTreeHash = fingerprint.treeHash;
3254
- const generation = planWikiGeneration(codewiki, input.depth ?? "auto");
3255
- progress2(input, {
3256
- phase: "codewiki",
3257
- status: "completed",
3258
- message: `loaded ${indexedSourceFileCount2(codewiki)} source file${indexedSourceFileCount2(codewiki) === 1 ? "" : "s"}`,
3259
- current: indexedSourceFileCount2(codewiki),
3260
- total: indexedSourceFileCount2(codewiki)
3261
- });
3262
- const staging = adoptOrCreateStaging(cwd);
3263
- const resolved = resolvePlan({
3264
- cwd,
3265
- stagingDir: staging.dir,
3266
- adopted: staging.adopted,
3267
- mode,
3268
- candidate: generation.plan,
3269
- previousPlan: existingMeta?.plan,
3270
- gitHead: existingMeta?.gitHead ?? null
3271
- });
3272
- const owed = resolved.plan.pages.filter((page) => page.status !== "written").length;
3273
- progress2(input, {
3274
- phase: "codewiki",
3275
- status: "running",
3276
- message: `selected ${generation.depth} wiki strategy`,
3277
- detail: `${generation.sourceFiles} source files; ${generation.sourceLines} lines; ${resolved.plan.pages.length} pages planned; ${owed} to write` + (resolved.resumed ? "; resuming an interrupted run" : "")
3278
- });
3279
- writeWikiPlanFile(staging.dir, resolved.plan);
3280
- const beforeHash = computeWikiContentHash(cwd);
3281
- if (!input.generate) {
3282
- const problem = "wiki generation requires a model runtime";
3283
- progress2(input, { phase: "generate", status: "failed", message: problem });
3284
- progress2(input, { phase: "done", status: "failed", message: "wiki generation failed" });
3285
- return failed([problem], listWikiPagesInDir(wikiDir(cwd)).length);
3286
- }
3287
- progress2(input, {
3288
- phase: "generate",
3289
- status: "started",
3290
- message: mode === "init" ? "drafting project wiki" : "updating project wiki"
3291
- });
3292
- try {
3293
- await input.generate({
3294
- cwd,
3295
- mode,
3296
- outputDir: staging.dir,
3297
- codewiki,
3298
- generation,
3299
- plan: resolved.plan,
3300
- resumed: resolved.resumed,
3301
- unclaimedAreas: resolved.unclaimedAreas,
3302
- ...input.decisions ? { decisions: input.decisions } : {},
3303
- gitHead: existingMeta?.gitHead ?? null,
3304
- ...input.onProgress ? { progress: input.onProgress } : {}
3305
- });
3306
- } catch (err) {
3307
- const problem = err instanceof Error ? err.message : String(err);
3308
- progress2(input, { phase: "generate", status: "failed", message: "wiki generator failed", detail: problem });
3309
- progress2(input, {
3310
- phase: "done",
3311
- status: "failed",
3312
- message: "wiki generation failed",
3313
- detail: `staged work kept at ${staging.dir}; rerun to resume`
3314
- });
3315
- return failed([problem], listWikiPagesInDir(wikiDir(cwd)).length);
3316
- }
3317
- progress2(input, { phase: "generate", status: "completed", message: "wiki generator completed" });
3318
- const workedPlan = readWikiPlanFile(staging.dir, resolved.plan) ?? resolved.plan;
3319
- const report = assembleWikiTree({ dir: staging.dir, sourceRoot: cwd, plan: workedPlan });
3320
- const finalPlan = reconcilePlan(workedPlan, staging.dir);
3321
- const pendingCount = finalPlan.pages.filter((page) => page.status !== "written").length;
3322
- progress2(input, {
3323
- phase: "state",
3324
- status: "running",
3325
- message: `assembled ${report.pages.length} page${report.pages.length === 1 ? "" : "s"}`,
3326
- detail: `${report.repaired} repaired; ${report.issues.length} unresolved reference${report.issues.length === 1 ? "" : "s"}` + (report.dropped.length > 0 ? `; ${report.dropped.length} empty page dropped` : "") + (pendingCount > 0 ? `; ${pendingCount} page${pendingCount === 1 ? "" : "s"} still to write` : "")
3327
- });
3328
- rmSync3(join9(staging.dir, WIKI_PLAN_FILE), { force: true });
3329
- const afterHash = computeWikiContentHashOfDir(staging.dir);
3330
- const stagedPages = listWikiPagesInDir(staging.dir);
3331
- const problems = report.issues.map((issue) => `${issue.page} has an unresolved ${issue.kind}: ${issue.reference}`);
3332
- const writeMeta = () => {
3333
- writeWikiMeta(cwd, {
3334
- version: 1,
3335
- updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3336
- gitHead: currentWikiGitHead(cwd),
3337
- sourceTreeHash,
3338
- model: input.model,
3339
- contentHash: afterHash,
3340
- pages: stagedPages,
3341
- generation: {
3342
- requestedDepth: generation.requestedDepth,
3343
- depth: generation.depth,
3344
- sourceFiles: generation.sourceFiles,
3345
- sourceLines: generation.sourceLines,
3346
- pagesPlanned: finalPlan.pages.length,
3347
- pagesWritten: finalPlan.pages.length - pendingCount
3348
- },
3349
- plan: finalPlan
3350
- });
3351
- };
3352
- const done = (status) => ({
3353
- status,
3354
- pages: stagedPages.length,
3355
- pending: pendingCount,
3356
- ...problems.length > 0 ? { problems } : {}
3357
- });
3358
- if (afterHash === beforeHash && computeWikiContentHash(cwd) === beforeHash && existingMeta) {
3359
- removeDir(staging.dir);
3360
- progress2(input, {
3361
- phase: "state",
3362
- status: "completed",
3363
- message: "wiki unchanged; metadata preserved",
3364
- detail: wikiMetaPath(cwd)
3365
- });
3366
- progress2(input, { phase: "done", status: "completed", message: "wiki unchanged" });
3367
- return done("noop");
3368
- }
3369
- progress2(input, { phase: "state", status: "running", message: "promoting wiki" });
3370
- const promoted = promoteStaging(cwd, staging.dir, writeMeta);
3371
- if (!promoted.ok) {
3372
- progress2(input, {
3373
- phase: "done",
3374
- status: "failed",
3375
- message: "wiki promotion failed",
3376
- detail: promoted.problems.join("; ")
3377
- });
3378
- return failed(promoted.problems, listWikiPagesInDir(wikiDir(cwd)).length);
3379
- }
3380
- progress2(input, { phase: "state", status: "completed", message: "wiki metadata written" });
3381
- progress2(input, {
3382
- phase: "done",
3383
- status: "completed",
3384
- message: pendingCount > 0 ? "wiki partially generated" : "wiki generated",
3385
- ...pendingCount > 0 ? {
3386
- detail: `${pendingCount} page${pendingCount === 1 ? "" : "s"} remain; run \`clio-coder context wiki --update\` to finish`
3387
- } : {}
3388
- });
3389
- return done("generated");
3390
- } finally {
3391
- lock.release();
3392
- }
3393
- }
3394
-
3395
- // src/domains/context/refresh.ts
3396
- function curateClioMd(cwd, codewiki) {
3397
- try {
3398
- const parsed = tryReadClioMd(cwd);
3399
- if (!parsed?.ok) return "absent";
3400
- const handbook = parsed.value;
3401
- const fresh = new Map(codewikiSections(codewiki).map((section) => [section.title, section.body]));
3402
- let changed = false;
3403
- const sections = handbook.sections.map((section) => {
3404
- const body = fresh.get(section.title);
3405
- if (body === void 0 || body === section.body) return section;
3406
- changed = true;
3407
- return { title: section.title, body };
3408
- });
3409
- if (!changed) return "unchanged";
3410
- writeFileSync3(
3411
- join10(cwd, "CLIO-CODER.md"),
3412
- serializeClioMd({
3413
- projectName: handbook.projectName,
3414
- identity: handbook.identity,
3415
- conventions: handbook.conventions,
3416
- invariants: handbook.invariants,
3417
- sections,
3418
- ...handbook.importedAgentContext ? { importedAgentContext: handbook.importedAgentContext } : {},
3419
- fingerprint: handbook.fingerprint
3420
- }),
3421
- "utf8"
3422
- );
3423
- return "updated";
3424
- } catch {
3425
- return "absent";
3426
- }
3427
- }
3428
- function indexedSourceFileCount3(codewiki) {
3429
- return codewiki.files.filter((file) => file.lang !== "config").length;
3430
- }
3431
- var STALE_WIKI_REFRESH_HINT = "wiki is stale; run clio-coder context refresh --wiki or clio-coder context wiki --update";
3432
- var NO_WIKI_HINT = "no wiki exists, so --wiki had nothing to update; run clio-coder context wiki to build one";
3433
- function incompleteWikiHint(cwd) {
3434
- const completeness = wikiCompleteness(cwd);
3435
- if (!completeness || completeness.owed === 0) return void 0;
3436
- return `wiki is incomplete: ${completeness.pagesWritten} of ${completeness.pagesPlanned} planned pages written, ${completeness.owed} owed; run clio-coder context wiki --update to resume`;
3437
- }
3438
- async function runContextRefresh(input = {}) {
3439
- const cwd = input.cwd ?? process.cwd();
3440
- const now = input.now ?? (() => /* @__PURE__ */ new Date());
3441
- const prev = readClioState(cwd);
3442
- const hasWiki = readWikiMeta(cwd) !== null;
3443
- const projectType = prev?.projectType ?? detectProjectType(cwd);
3444
- const indexedAt = now().toISOString();
3445
- input.onProgress?.({ phase: "codewiki", status: "started", message: "rebuilding codewiki" });
3446
- let fingerprint;
3447
- let clioMd = "absent";
3448
- const coordinated = await coordinateCodewikiWrite(cwd, () => ({ kind: "build", cwd, language: projectType }), {
3449
- afterCommit: (result, workspace) => {
3450
- fingerprint = result.fingerprint;
3451
- clioMd = curateClioMd(workspace, result.codewiki);
3452
- input.onProgress?.({ phase: "state", status: "running", message: "writing state" });
3453
- const latest = readClioState(workspace);
3454
- writeClioState(workspace, {
3455
- version: 1,
3456
- projectType,
3457
- fingerprint: result.fingerprint,
3458
- codewikiVersion: result.codewiki.version,
3459
- ...latest?.contextSources ? { contextSources: latest.contextSources } : {},
3460
- ...latest?.contextSourceHash ? { contextSourceHash: latest.contextSourceHash } : {},
3461
- ...latest?.lastBootstrap ? { lastBootstrap: latest.lastBootstrap } : {},
3462
- ...latest?.lastInitAt ? { lastInitAt: latest.lastInitAt } : {},
3463
- lastSessionAt: latest?.lastSessionAt ?? indexedAt,
3464
- lastIndexedAt: indexedAt
3465
- });
3466
- }
3467
- });
3468
- if (!coordinated || !fingerprint) throw new Error("codewiki refresh transaction did not commit");
3469
- const codewiki = coordinated.codewiki;
3470
- const entries = indexedSourceFileCount3(codewiki);
3471
- let wikiResult;
3472
- let hint;
3473
- if (input.wiki === true && hasWiki) {
3474
- wikiResult = await runWikiGenerate({
3475
- cwd,
3476
- mode: "update",
3477
- ...input.decisions ? { decisions: input.decisions } : {},
3478
- model: input.wikiModel ?? "unresolved-documenter-target",
3479
- ...input.wikiGenerate ? { generate: input.wikiGenerate } : {},
3480
- ...input.onProgress ? { onProgress: input.onProgress } : {}
3481
- });
3482
- } else if (input.wiki === true) {
3483
- hint = NO_WIKI_HINT;
3484
- } else if (hasWiki) {
3485
- hint = incompleteWikiHint(cwd) ?? (wikiStaleness(cwd).state === "stale" ? STALE_WIKI_REFRESH_HINT : void 0);
3486
- }
3487
- const committedClioMd = clioMd;
3488
- const handbookNote = committedClioMd === "updated" ? "; CLIO-CODER.md index sections updated" : "";
3489
- input.io?.stdout(
3490
- `clio-coder context refresh: codewiki rebuilt (${entries} source file${entries === 1 ? "" : "s"})${handbookNote}
3491
- `
3492
- );
3493
- input.onProgress?.({ phase: "done", status: "completed", message: "context refreshed" });
3494
- return {
3495
- action: "refreshed",
3496
- codewikiEntries: entries,
3497
- fingerprint,
3498
- clioMd: committedClioMd,
3499
- ...wikiResult ? { wiki: wikiResult } : {},
3500
- ...hint ? { hint } : {}
3501
- };
3502
- }
3503
-
3504
- // src/domains/context/runtime.ts
3505
- init_esm_shims();
3506
-
3507
- // src/domains/context/extension.ts
3508
- init_esm_shims();
3509
- import { existsSync as existsSync8 } from "node:fs";
3510
- import { isAbsolute, join as join11, relative as relative4, resolve as resolve3 } from "node:path";
3511
- function persistState(cwd, fingerprint, indexedAt, prev, codewikiVersion, projectType) {
3512
- writeClioState(cwd, {
3513
- version: 1,
3514
- projectType: prev?.projectType ?? projectType,
3515
- fingerprint,
3516
- codewikiVersion,
3517
- ...prev?.contextSources ? { contextSources: prev.contextSources } : {},
3518
- ...prev?.contextSourceHash ? { contextSourceHash: prev.contextSourceHash } : {},
3519
- ...prev?.lastBootstrap ? { lastBootstrap: prev.lastBootstrap } : {},
3520
- ...prev?.lastInitAt ? { lastInitAt: prev.lastInitAt } : {},
3521
- lastSessionAt: prev?.lastSessionAt ?? (/* @__PURE__ */ new Date()).toISOString(),
3522
- lastIndexedAt: indexedAt
3523
- });
3524
- }
3525
- async function ensureCodewikiFresh(cwd) {
3526
- const state = readClioState(cwd);
3527
- if (!state && !existsSync8(codewikiPath(cwd))) return;
3528
- const indexedAt = (/* @__PURE__ */ new Date()).toISOString();
3529
- await coordinateCodewikiWrite(
3530
- cwd,
3531
- (current, workspace) => {
3532
- const language = readClioState(workspace)?.projectType ?? current?.language;
3533
- return {
3534
- kind: "ensure",
3535
- cwd,
3536
- ...language ? { language } : {},
3537
- current,
3538
- previous: readClioState(workspace)?.fingerprint ?? null
3539
- };
3540
- },
3541
- {
3542
- afterCommit: ({ codewiki, fingerprint }, workspace) => persistState(workspace, fingerprint, indexedAt, readClioState(workspace), codewiki.version, codewiki.language)
3543
- }
3544
- );
3545
- }
3546
- var CONTEXT_STATE_CACHE_TTL_MS = 1500;
3547
- function memoryCount() {
3548
- try {
3549
- return loadMemoryRecordsSync(clioDataDir()).length;
3550
- } catch {
3551
- return 0;
3552
- }
3553
- }
3554
- function resolveClioMdState(cwd) {
3555
- const clio = loadProjectClioMd(cwd);
3556
- if (clio.files.length === 0 && clio.errors.length === 0) return "none";
3557
- if (clio.errors.length > 0) return "malformed";
3558
- const state = readClioState(cwd);
3559
- const localStandardIsEffective = clio.files.some((file) => file.path === join11(resolve3(cwd), "CLIO-CODER.md"));
3560
- if (localStandardIsEffective && state?.contextSources !== void 0 && adoptionSourcesChanged(state.contextSources, { cwd })) {
3561
- return "stale";
3562
- }
3563
- return "ok";
3564
- }
3565
- function createContextStateReader() {
3566
- let cached = null;
3567
- return {
3568
- read(cwd = process.cwd()) {
3569
- const now = Date.now();
3570
- if (cached && cached.cwd === cwd && now - cached.at < CONTEXT_STATE_CACHE_TTL_MS) return cached.state;
3571
- const state = { clioMd: resolveClioMdState(cwd), memoryCount: memoryCount() };
3572
- cached = { cwd, at: now, state };
3573
- return state;
3574
- },
3575
- invalidate(cwd) {
3576
- if (!cached) return;
3577
- if (!cwd || cached.cwd === cwd) cached = null;
3578
- }
3579
- };
3580
- }
3581
- function collectStartupHints(cwd, options = {}) {
3582
- const hints = [];
3583
- let projectType;
3584
- try {
3585
- projectType = detectProjectType(cwd);
3586
- } catch {
3587
- projectType = "unknown";
3588
- }
3589
- const clio = loadProjectClioMd(cwd);
3590
- if (clio.files.length === 0 && clio.errors.length === 0 && projectType !== "unknown" && options.noContextFiles !== true) {
3591
- hints.push("clio-coder: No CLIO-CODER.md detected. Run /context init to explore the repo and bootstrap context.");
3592
- }
3593
- for (const issue of clio.errors) {
3594
- hints.push(`clio-coder: malformed ${issue.path} ignored: ${issue.error}`);
3595
- }
3596
- const contract = loadValidationContract(cwd);
3597
- if (!contract.ok) {
3598
- hints.push(`clio-coder: validation contract ignored, rigor stays normal: ${describeValidationContract(contract)}`);
3599
- }
3600
- const state = readClioState(cwd);
3601
- if (!state) return hints;
3602
- if (state.contextSources !== void 0 && adoptionSourcesChanged(state.contextSources, { cwd })) {
3603
- hints.push("clio-coder: Imported agent context changed. Run /context init --adopt to refresh.");
3604
- }
3605
- return hints;
3606
- }
3607
- function createContextBundle(_context, options = {}) {
3608
- let lastCwd = process.cwd();
3609
- let stopping = false;
3610
- let startupHints = [];
3611
- const contextState = createContextStateReader();
3612
- const onStart = () => {
3613
- lastCwd = process.cwd();
3614
- void ensureCodewikiFresh(lastCwd).catch(() => {
3615
- });
3616
- startupHints = collectStartupHints(lastCwd, options);
3617
- if (process.env.CLIO_CODER_INTERACTIVE === "1") return;
3618
- for (const hint of startupHints) process.stderr.write(`${hint}
3619
- `);
3620
- };
3621
- let incrementalQueue = Promise.resolve();
3622
- const noteFileChanges = (paths, cwd = lastCwd) => {
3623
- if (stopping) return;
3624
- const workspace = resolve3(cwd);
3625
- incrementalQueue = incrementalQueue.then(async () => {
3626
- if (paths.length === 0) return;
3627
- const rel = paths.map((p) => isAbsolute(p) ? relative4(workspace, p) : p).filter((p) => p.length > 0 && !p.startsWith(".."));
3628
- await coordinateCodewikiWrite(
3629
- workspace,
3630
- (current) => current ? { kind: "incremental", cwd: workspace, current, paths: rel } : null,
3631
- {
3632
- requireExisting: true,
3633
- afterCommit: ({ codewiki, fingerprint, changed }, committedWorkspace) => {
3634
- if (!changed) return;
3635
- persistState(
3636
- committedWorkspace,
3637
- fingerprint,
3638
- (/* @__PURE__ */ new Date()).toISOString(),
3639
- readClioState(committedWorkspace),
3640
- codewiki.version,
3641
- codewiki.language
3642
- );
3643
- }
3644
- }
3645
- );
3646
- contextState.invalidate(workspace);
3647
- }).catch(() => {
3648
- });
3649
- };
3650
- let unsubscribeSessionStart = null;
3651
- const extension = {
3652
- start() {
3653
- unsubscribeSessionStart = _context.bus.on(BusChannels.SessionStart, onStart);
3654
- },
3655
- async stop() {
3656
- stopping = true;
3657
- unsubscribeSessionStart?.();
3658
- unsubscribeSessionStart = null;
3659
- await Promise.all([incrementalQueue, drainCodewikiWrites(lastCwd)]);
3660
- const state = readClioState(lastCwd);
3661
- if (!state) return;
3662
- writeClioState(lastCwd, { ...state, lastSessionAt: (/* @__PURE__ */ new Date()).toISOString() });
3663
- }
3664
- };
3665
- const contract = {
3666
- async runBootstrap(input) {
3667
- const emitProgress = (event) => {
3668
- _context.bus.emit(BusChannels.ContextActivity, { kind: "context-init", at: Date.now(), ...event });
3669
- input?.onProgress?.(event);
3670
- };
3671
- try {
3672
- const result = await runBootstrap(input ? { ...input, onProgress: emitProgress } : { onProgress: emitProgress });
3673
- const cwd = input?.cwd ?? process.cwd();
3674
- contextState.invalidate(cwd);
3675
- if (cwd === lastCwd) startupHints = collectStartupHints(cwd, options);
3676
- return result;
3677
- } catch (err) {
3678
- emitProgress({
3679
- phase: "done",
3680
- status: "failed",
3681
- message: "context init failed",
3682
- detail: err instanceof Error ? err.message : String(err)
3683
- });
3684
- throw err;
3685
- }
3686
- },
3687
- async runContextClear(input) {
3688
- const emitProgress = (event) => {
3689
- _context.bus.emit(BusChannels.ContextActivity, { kind: "context-clear", at: Date.now(), ...event });
3690
- };
3691
- emitProgress({ phase: "done", status: "started", message: "clearing context" });
3692
- try {
3693
- const result = await runContextClear(input);
3694
- const cwd = input?.cwd ?? process.cwd();
3695
- contextState.invalidate(cwd);
3696
- if (cwd === lastCwd) startupHints = collectStartupHints(cwd, options);
3697
- emitProgress({ phase: "done", status: "completed", message: "context cleared" });
3698
- return result;
3699
- } catch (err) {
3700
- emitProgress({
3701
- phase: "done",
3702
- status: "failed",
3703
- message: "context clear failed",
3704
- detail: err instanceof Error ? err.message : String(err)
3705
- });
3706
- throw err;
3707
- }
3708
- },
3709
- async runContextRefresh(input) {
3710
- const emitProgress = (event) => {
3711
- _context.bus.emit(BusChannels.ContextActivity, { kind: "context-refresh", at: Date.now(), ...event });
3712
- input?.onProgress?.(event);
3713
- };
3714
- try {
3715
- const result = await runContextRefresh({
3716
- ...input,
3717
- ...input?.wiki ? { decisions: input.decisions ?? await currentDecisions(_context) } : {},
3718
- onProgress: emitProgress
3719
- });
3720
- const cwd = input?.cwd ?? process.cwd();
3721
- contextState.invalidate(cwd);
3722
- if (cwd === lastCwd) startupHints = collectStartupHints(cwd, options);
3723
- return result;
3724
- } catch (err) {
3725
- emitProgress({
3726
- phase: "done",
3727
- status: "failed",
3728
- message: "context refresh failed",
3729
- detail: err instanceof Error ? err.message : String(err)
3730
- });
3731
- throw err;
3732
- }
3733
- },
3734
- async runWikiGenerate(input) {
3735
- const emitProgress = (event) => {
3736
- _context.bus.emit(BusChannels.ContextActivity, { kind: "context-wiki", at: Date.now(), ...event });
3737
- input?.onProgress?.(event);
3738
- };
3739
- try {
3740
- return await runWikiGenerate({
3741
- ...input ?? { model: "configured-clio-target" },
3742
- decisions: input?.decisions ?? await currentDecisions(_context),
3743
- onProgress: emitProgress
3744
- });
3745
- } catch (err) {
3746
- emitProgress({
3747
- phase: "done",
3748
- status: "failed",
3749
- message: "context wiki failed",
3750
- detail: err instanceof Error ? err.message : String(err)
3751
- });
3752
- throw err;
3753
- }
3754
- },
3755
- renderPromptContext,
3756
- projectStructuredContext(cwd = process.cwd()) {
3757
- const clio = loadProjectClioMd(cwd).value;
3758
- if (!clio) return null;
3759
- const verificationBody = clio.sections.filter((section) => section.title.toLowerCase() === "verification expectations").map((section) => section.body.trim()).filter((body) => body.length > 0).join("\n\n");
3760
- return {
3761
- projectName: clio.projectName,
3762
- conventions: [...clio.conventions],
3763
- invariants: [...clio.invariants],
3764
- ...verificationBody.length > 0 ? { verificationExpectations: verificationBody } : {}
3765
- };
3766
- },
3767
- contextState: contextState.read,
3768
- startupHints: () => [...startupHints],
3769
- noteFileChanges
3770
- };
3771
- return { extension, contract };
3772
- }
3773
- async function currentDecisions(context) {
3774
- const session = context.getContract("session");
3775
- const current = session?.current();
3776
- if (!session || !current) return [];
3777
- session.flushAppends?.();
3778
- const read = await readSessionEntriesForId(clioStateDir(), current.id);
3779
- return foldDecisionBoard(filterEntriesToActivePath(read.entries, session.tree(current.id).leafId ?? void 0));
3780
- }
3781
-
3782
- // src/domains/context/manifest.ts
3783
- init_esm_shims();
3784
- var ContextManifest = {
3785
- name: "context",
3786
- dependsOn: ["resources"]
3787
- };
3788
-
3789
- // src/domains/context/runtime.ts
3790
- var ContextDomainModule = {
3791
- manifest: ContextManifest,
3792
- createExtension: createContextBundle
3793
- };
3794
- function createContextDomainModule(options = {}) {
3795
- return {
3796
- manifest: ContextManifest,
3797
- createExtension: (context) => createContextBundle(context, options)
3798
- };
3799
- }
3800
-
3801
- // src/domains/context/wiki/prompts.ts
3802
- init_esm_shims();
3803
- import { execFileSync as execFileSync2 } from "node:child_process";
3804
- import { existsSync as existsSync9, realpathSync, statSync as statSync4 } from "node:fs";
3805
- import { isAbsolute as isAbsolute2, join as join12, relative as relative5 } from "node:path";
3806
- function readWikiFragment(fragment, substitutions) {
3807
- const id = `wiki.${fragment}`;
3808
- const loaded = loadFragments().byId.get(id);
3809
- if (!loaded) {
3810
- throw new Error(`context/wiki: fragment "${id}" not found; check prompts/fragments/wiki/${fragment}.md frontmatter`);
3811
- }
3812
- let text = loaded.body.trim();
3813
- for (const [token, value] of Object.entries(substitutions)) {
3814
- text = text.split(`{{${token}}}`).join(value);
3815
- }
3816
- return text;
3817
- }
3818
- var REPOSITORY_GUIDANCE_CANDIDATES = [
3819
- ".claude/CLAUDE.md",
3820
- "AGENTS.md",
3821
- "CLAUDE.md",
3822
- "CLIO-CODER.md",
3823
- "CODEX.md",
3824
- ".codex/AGENTS.md",
3825
- "GEMINI.md",
3826
- ".github/copilot-instructions.md"
3827
- ];
3828
- function isWithin(root, candidate) {
3829
- const rel = relative5(root, candidate);
3830
- return rel.length === 0 || !rel.startsWith("..") && !isAbsolute2(rel);
3831
- }
3832
- function repositoryGuidancePaths(cwd) {
3833
- let root;
3834
- try {
3835
- root = realpathSync(cwd);
3836
- } catch {
3837
- return [];
3838
- }
3839
- const seen = /* @__PURE__ */ new Set();
3840
- const paths = [];
3841
- for (const relPath of REPOSITORY_GUIDANCE_CANDIDATES) {
3842
- const absPath = join12(cwd, relPath);
3843
- if (!existsSync9(absPath)) continue;
3844
- try {
3845
- const resolved = realpathSync(absPath);
3846
- const stat = statSync4(resolved);
3847
- if (!isWithin(root, resolved) || !stat.isFile() || stat.size === 0 || seen.has(resolved)) continue;
3848
- seen.add(resolved);
3849
- paths.push(relPath);
3850
- } catch {
3851
- }
3852
- }
3853
- return paths;
3854
- }
3855
- function repositoryGuidance(cwd) {
3856
- const paths = repositoryGuidancePaths(cwd);
3857
- if (paths.length === 0) {
3858
- return "No recognized repository instruction files were detected. Discover source-of-truth documentation from the live tree.";
3859
- }
3860
- return [
3861
- "Read every detected instruction file before drafting:",
3862
- ...paths.map((path) => `- ${path}`),
3863
- "Treat these files as repository instructions, not implementation proof. If one designates a planning, specification, or engineering-truth authority, read that authority before making status claims, then verify mutable implementation claims against live source, configuration, and tests."
3864
- ].join("\n");
3865
- }
3866
- function gitLines(cwd, args, cap) {
3867
- try {
3868
- const out3 = execFileSync2("git", [...args], {
3869
- cwd,
3870
- encoding: "utf8",
3871
- stdio: ["ignore", "pipe", "ignore"]
3872
- }).trimEnd();
3873
- const lines = out3.split(/\r?\n/).filter((line) => line.length > 0);
3874
- if (lines.length === 0) return "";
3875
- const capped = lines.slice(0, cap);
3876
- return `${capped.join("\n")}${lines.length > capped.length ? `
3877
- [truncated to ${cap} lines]` : ""}`;
3878
- } catch {
3879
- return null;
3880
- }
3881
- }
3882
- function workingTreeEvidence(cwd) {
3883
- const out3 = gitLines(cwd, ["status", "--short", "--untracked-files=all"], 200);
3884
- if (out3 === null) return "Working-tree evidence unavailable: git status failed.";
3885
- return out3.length === 0 ? "Working tree is clean." : out3;
3886
- }
3887
- function gitEvidence(cwd, gitHead) {
3888
- if (!gitHead) return "Git evidence unavailable: no previous wiki gitHead was recorded.";
3889
- const out3 = gitLines(cwd, ["log", `${gitHead}..HEAD`, "--name-status", "--oneline"], 200);
3890
- if (out3 === null) return "Git evidence unavailable: git log failed for the recorded wiki gitHead.";
3891
- return out3.length === 0 ? "Git evidence is empty: no commits were found since the recorded wiki gitHead." : out3;
3892
- }
3893
- function renderPlanSkeleton(plan) {
3894
- return JSON.stringify(
3895
- {
3896
- overview: plan.overview,
3897
- pages: plan.pages.map((page) => ({
3898
- path: page.path,
3899
- title: page.title,
3900
- intent: page.intent,
3901
- sources: page.sources
3902
- }))
3903
- },
3904
- null,
3905
- 2
3906
- );
3907
- }
3908
- function buildWikiPlanPrompt(input) {
3909
- const { generation } = input;
3910
- const plan = input.plan ?? generation.plan;
3911
- const unclaimed = input.unclaimedAreas ?? [];
3912
- const sections = [
3913
- readWikiFragment("plan", { planPath: join12(input.outputDir, WIKI_PLAN_FILE) }),
3914
- "## Repository scale",
3915
- `${generation.sourceFiles} indexed source files, ${generation.sourceLines} source lines, decomposed at ${generation.depth} depth into ${generation.plan.pages.length} candidate pages.`,
3916
- "## Candidate plan",
3917
- "```json",
3918
- renderPlanSkeleton(plan),
3919
- "```"
3920
- ];
3921
- if (unclaimed.length > 0) {
3922
- sections.push(
3923
- "## Areas no page covers",
3924
- "The index found these areas and no page in the plan above claims any of their sources. Add a page for each one that deserves its own, or fold it into an existing page by extending that page's sources.",
3925
- unclaimed.map((page) => `- ${page.path} (${page.title}): ${page.sources.join(", ")}`).join("\n")
3926
- );
3927
- }
3928
- sections.push(
3929
- "## Repository guidance",
3930
- repositoryGuidance(input.cwd),
3931
- "## Working-tree evidence",
3932
- "```text",
3933
- workingTreeEvidence(input.cwd),
3934
- "```",
3935
- "## Codewiki digest",
3936
- "```text",
3937
- renderCodewikiDigest(input.codewiki),
3938
- "```"
3939
- );
3940
- if (input.mode === "update") {
3941
- sections.push("## Git evidence", "```text", gitEvidence(input.cwd, input.gitHead), "```");
3942
- }
3943
- return `${sections.join("\n\n")}
3944
- `;
3945
- }
3946
- function scopedSymbols(codewiki, sources, limit = 60) {
3947
- const wanted = new Set(sources);
3948
- const fileById = new Map(codewiki.files.map((file) => [file.id, file]));
3949
- const lines = [];
3950
- for (const symbol of codewiki.symbols) {
3951
- const file = fileById.get(symbol.fileId);
3952
- if (!file || !wanted.has(file.path)) continue;
3953
- lines.push(`- ${symbol.name} ${symbol.kind} ${file.path}:${symbol.line}`);
3954
- if (lines.length >= limit) break;
3955
- }
3956
- return lines.length > 0 ? lines.join("\n") : "No indexed symbols for these paths; read the files directly.";
3957
- }
3958
- function buildWikiPagePrompt(input) {
3959
- const { page } = input;
3960
- const siblingLines = input.siblings.filter((sibling) => sibling.path !== page.path).map((sibling) => `- ${sibling.path} \u2014 ${sibling.title}`);
3961
- const sections = [
3962
- readWikiFragment("page", {
3963
- pagePath: join12(input.outputDir, page.path),
3964
- pageRelPath: page.path,
3965
- pageTitle: page.title
3966
- }),
3967
- "## What this page must document",
3968
- page.intent.length > 0 ? page.intent : `Document ${page.title}.`,
3969
- "## Anchor sources",
3970
- page.sources.length > 0 ? `Read every one of these before writing, then follow at least one call in each direction:
3971
- ${page.sources.map((source) => `- ${source}`).join("\n")}` : "No anchor sources were planned. Use `code_nav` to locate this page's subject before writing.",
3972
- "## Indexed symbols under those sources",
3973
- "```text",
3974
- scopedSymbols(input.codewiki, page.sources),
3975
- "```",
3976
- "## Other pages you may link to",
3977
- siblingLines.length > 0 ? siblingLines.join("\n") : "None; this is the only page in the plan.",
3978
- "## Repository guidance",
3979
- repositoryGuidance(input.cwd)
3980
- ];
3981
- const decisions = recordedDecisions(input);
3982
- if (decisions.length > 0) sections.push("# Recorded decisions", "```json", JSON.stringify(decisions, null, 2), "```");
3983
- if (input.seeded) {
3984
- sections.push(
3985
- "## Revision",
3986
- `A previous version of this page is already at ${join12(input.outputDir, page.path)}. Read it first and revise it in place. Correct what the current source contradicts and fill what it omits; keep accurate prose as it stands.`
3987
- );
3988
- }
3989
- return `${sections.join("\n\n")}
3990
- `;
3991
- }
3992
- function underSource(path, source) {
3993
- const root = source.replace(/^\.\//, "").replace(/\/$/, "");
3994
- const candidate = path.replace(/^\.\//, "");
3995
- return candidate === root || candidate.startsWith(`${root}/`);
3996
- }
3997
- function recordedDecisions(input) {
3998
- const files = new Set(
3999
- input.codewiki.files.filter((file) => input.page.sources.some((source) => underSource(file.path, source))).map((file) => file.id)
4000
- );
4001
- const symbols = new Set(
4002
- input.codewiki.symbols.filter((symbol) => files.has(symbol.fileId)).map((symbol) => symbol.name)
4003
- );
4004
- return (input.decisions ?? []).flatMap(
4005
- (entry) => entry.decisions.filter((record) => {
4006
- if (record.status !== "active") return false;
4007
- if (symbols.has(record.key)) return true;
4008
- const paths = [record.rationale ?? "", ...record.alternatives ?? []].join(" ").match(/[\w@./-]+/g) ?? [];
4009
- return paths.some((path) => input.page.sources.some((source) => underSource(path.replace(/\.$/, ""), source)));
4010
- }).map((record) => ({
4011
- ref: decisionRef(entry.interviewId, record.key),
4012
- key: record.key,
4013
- value: record.value,
4014
- alternatives: record.alternatives ?? [],
4015
- rationale: record.rationale ?? record.source_question ?? "",
4016
- decidedAt: record.decidedAt,
4017
- source: record.source ?? (entry.origin === "agent" ? "agent" : "operator")
4018
- }))
4019
- ).slice(0, 12);
4020
- }
4021
-
4022
- export {
4023
- adoptionSnapshotsHash,
4024
- scanAgentConfigs,
4025
- renderImportedAgentContext,
4026
- adoptionSourcesChanged,
4027
- parseClioMd,
4028
- serializeClioMd,
4029
- loadProjectClioMd,
4030
- tryReadClioMd,
4031
- renderPromptContext,
4032
- fallbackBootstrapOutput,
4033
- runBootstrap,
4034
- runContextClear,
4035
- OPERATOR_PROFILE_MAX_CHARS,
4036
- loadOperatorProfile,
4037
- renderOperatorProfile,
4038
- loadProjectRules,
4039
- selectActiveRules,
4040
- assembleWikiTree,
4041
- runWikiGenerate,
4042
- runContextRefresh,
4043
- ContextDomainModule,
4044
- createContextDomainModule,
4045
- buildWikiPlanPrompt,
4046
- buildWikiPagePrompt
4047
- };
4048
- //# sourceMappingURL=chunk-IZXGRF7P.js.map