@iowarp/clio-coder 0.4.8 → 0.4.9

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 (513) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +7 -6
  3. package/dist/{acp-JWPQZM2D.js → acp-ZWZCPS2A.js} +13 -13
  4. package/dist/{agents-4GCDIRVX.js → agents-LYSOWZUE.js} +53 -52
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-SYAKTDQE.js → auth-WBQGKWQ5.js} +27 -27
  7. package/dist/{background-OW67WMYR.js → background-BUMOBAQN.js} +4 -4
  8. package/dist/{builtins-TKS63VNV.js → builtins-ODRJOEDI.js} +7 -7
  9. package/dist/{chunk-JLBVCROW.js → chunk-2DRRZ57Q.js} +33 -24
  10. package/dist/chunk-2JBZYUPY.js +105 -0
  11. package/dist/chunk-2KUBKL63.js +336 -0
  12. package/dist/{chunk-K45LHSCI.js → chunk-2VBWFXYE.js} +7 -3
  13. package/dist/{chunk-XTLJDC2X.js → chunk-2X2R3UTH.js} +23 -18
  14. package/dist/{chunk-5HULHKT2.js → chunk-37LW32LZ.js} +5 -5
  15. package/dist/{chunk-W7KNI3F5.js → chunk-3AND2EFU.js} +5 -5
  16. package/dist/{chunk-36XSBPXL.js → chunk-3RDHGNU7.js} +95 -27
  17. package/dist/{chunk-BIY22UUK.js → chunk-3SUDBGEI.js} +11 -10
  18. package/dist/{chunk-3IQOZRQ6.js → chunk-3TQN67I2.js} +7 -7
  19. package/dist/{chunk-KWJXCL2X.js → chunk-3U4BL2EV.js} +3 -3
  20. package/dist/{chunk-RBES4TCZ.js → chunk-3UQADNG2.js} +3 -3
  21. package/dist/{chunk-V4ZKOKRB.js → chunk-434LRQ6Z.js} +61 -53
  22. package/dist/{chunk-MWMW53WW.js → chunk-4ATBOFRP.js} +649 -193
  23. package/dist/{chunk-QGIC5SX5.js → chunk-4DNL43EZ.js} +3 -3
  24. package/dist/{chunk-GVU4CXPJ.js → chunk-4HFJKRGZ.js} +113 -54
  25. package/dist/{chunk-5A6XR3RJ.js → chunk-555E2WVV.js} +16 -2
  26. package/dist/{chunk-LZDLYSUN.js → chunk-5RTEFNBP.js} +3 -3
  27. package/dist/{chunk-HMGAKB7E.js → chunk-64XJW7NT.js} +15 -15
  28. package/dist/{chunk-EXKUF426.js → chunk-7FBCRWVT.js} +280 -280
  29. package/dist/{chunk-K3W6BF5C.js → chunk-7JSOSVLP.js} +2 -2
  30. package/dist/{chunk-WFTSK7N3.js → chunk-7N3OLLSL.js} +4 -4
  31. package/dist/{chunk-JRA6OBHY.js → chunk-A6DULIMH.js} +17 -5
  32. package/dist/{chunk-R5NRX5N4.js → chunk-AB3QXXBC.js} +2 -2
  33. package/dist/chunk-ACCECAH4.js +49 -0
  34. package/dist/{chunk-GJBJHJNY.js → chunk-AM6CEP2K.js} +5 -5
  35. package/dist/{chunk-MUXNDNMZ.js → chunk-AY4XE6GN.js} +19 -13
  36. package/dist/{chunk-MATCRH3M.js → chunk-BBA2TAWV.js} +9 -9
  37. package/dist/{chunk-PMUUAABD.js → chunk-BMNVVKEW.js} +9 -9
  38. package/dist/{chunk-TOPICHGR.js → chunk-CTGZCEI6.js} +2 -2
  39. package/dist/{chunk-L75H5B3B.js → chunk-DIAJYJYG.js} +2 -2
  40. package/dist/{chunk-JIMWEYWO.js → chunk-EHZRAB4U.js} +2 -2
  41. package/dist/{chunk-YXANQGCX.js → chunk-EM2DIQAJ.js} +6 -6
  42. package/dist/{chunk-JCVIL6TY.js → chunk-ETF4ROKH.js} +4 -4
  43. package/dist/{chunk-5W4FRA5Q.js → chunk-F2YM3JY4.js} +483 -253
  44. package/dist/{chunk-YGIV24MF.js → chunk-FEBQWHJT.js} +21 -16
  45. package/dist/{chunk-PGEFOTJB.js → chunk-FPS4R2RN.js} +5 -4
  46. package/dist/{chunk-XC5POIL4.js → chunk-G5R53COU.js} +1 -1
  47. package/dist/chunk-GHXGMFQ5.js +40 -0
  48. package/dist/{chunk-QLKCCC2J.js → chunk-GJDRMBDI.js} +14 -14
  49. package/dist/{chunk-2ZWLMA3T.js → chunk-GREYLTZ5.js} +7 -7
  50. package/dist/{chunk-YXFKLMX2.js → chunk-H2WSCZZT.js} +22 -6
  51. package/dist/{chunk-FNVPQQYT.js → chunk-H6IUCY6Q.js} +2 -2
  52. package/dist/{chunk-5C2OQHLR.js → chunk-H72DCH3E.js} +92 -203
  53. package/dist/{chunk-JYKUMHCQ.js → chunk-H7TXJR23.js} +21 -21
  54. package/dist/chunk-HBJQQTKM.js +40 -0
  55. package/dist/chunk-HCVKSGNZ.js +990 -0
  56. package/dist/{chunk-ARRUMZ7X.js → chunk-I47EJPYL.js} +3 -3
  57. package/dist/{chunk-YKIIWURD.js → chunk-IALGWTLO.js} +3 -3
  58. package/dist/{chunk-FB3KTE2J.js → chunk-IALZJE37.js} +4 -4
  59. package/dist/{chunk-RAUOKUZV.js → chunk-IC7JXLOM.js} +15 -10
  60. package/dist/{chunk-LLCGGVSW.js → chunk-IOSVTTCD.js} +7 -7
  61. package/dist/{chunk-DBREN25X.js → chunk-IPTPMLA6.js} +8 -3
  62. package/dist/{chunk-V552WL53.js → chunk-IZZI3SKQ.js} +3 -67
  63. package/dist/{chunk-UDAK6GR2.js → chunk-JIYWMQZ5.js} +2 -2
  64. package/dist/{chunk-O3HSB2YL.js → chunk-JKU34ACI.js} +2 -2
  65. package/dist/{chunk-6X7VOCDY.js → chunk-JTR3VSV3.js} +3 -3
  66. package/dist/{chunk-O2QJDRWP.js → chunk-JU6MAMRJ.js} +4 -4
  67. package/dist/chunk-JURMQWVJ.js +15 -0
  68. package/dist/{chunk-STC6CWUZ.js → chunk-K3XN4LZ4.js} +5 -5
  69. package/dist/{chunk-ATB3Q7YO.js → chunk-KIVFXGBM.js} +27 -2
  70. package/dist/{chunk-WJWNZXRM.js → chunk-KOAHT3N2.js} +2 -2
  71. package/dist/chunk-KP5BPXR3.js +73 -0
  72. package/dist/{chunk-K53E2PTW.js → chunk-KRJQG47M.js} +3 -3
  73. package/dist/{chunk-IILXVWJY.js → chunk-KW6OJ7IY.js} +19 -21
  74. package/dist/{chunk-A46ILRS2.js → chunk-L3NBWLSN.js} +4 -4
  75. package/dist/{chunk-2U2U5POA.js → chunk-L4RUTLRL.js} +5 -5
  76. package/dist/{chunk-QYSAZMSH.js → chunk-LGTVWPRN.js} +2 -2
  77. package/dist/{chunk-KGP3UQGJ.js → chunk-LSQW6KZO.js} +5 -5
  78. package/dist/{chunk-P4JS3MH5.js → chunk-LWJYOHT3.js} +8 -8
  79. package/dist/{chunk-U3TPUXOQ.js → chunk-M6YLF66Z.js} +74 -40
  80. package/dist/{chunk-5D2FNBMG.js → chunk-MJ4QEJVT.js} +2 -2
  81. package/dist/{chunk-RM3XJX7P.js → chunk-MO65K5CH.js} +5 -5
  82. package/dist/{chunk-H5DPSUBB.js → chunk-MTOZEQHL.js} +3 -3
  83. package/dist/{chunk-6R5MBXBJ.js → chunk-NBPA5QM6.js} +2 -2
  84. package/dist/{chunk-H77XBUBM.js → chunk-NMBEW4PP.js} +3 -3
  85. package/dist/{chunk-QWUSS2QP.js → chunk-NPLLK3HO.js} +67 -87
  86. package/dist/{chunk-K5UJD6MM.js → chunk-NSYGPIVW.js} +5 -5
  87. package/dist/{context-EZZPT2ZV.js → chunk-NXTV5OI5.js} +30 -84
  88. package/dist/{chunk-F7Y6QTPL.js → chunk-NYDG4QP4.js} +4 -4
  89. package/dist/{chunk-PFZJMXIY.js → chunk-OA2GDACN.js} +2 -2
  90. package/dist/{chunk-Q32C6AWI.js → chunk-PJI57EC6.js} +4 -4
  91. package/dist/{chunk-EFXMQYI6.js → chunk-PJJBUGMR.js} +52 -52
  92. package/dist/{chunk-ICYIUNO4.js → chunk-PNJE7JPS.js} +18 -3
  93. package/dist/chunk-PP23PZEV.js +1347 -0
  94. package/dist/chunk-PPIFDSBK.js +409 -0
  95. package/dist/{chunk-RFULVPBX.js → chunk-PTFISXQO.js} +6 -5
  96. package/dist/{chunk-JV25I7ID.js → chunk-QB33Z5S7.js} +5 -5
  97. package/dist/{chunk-D55WO5J7.js → chunk-QGNII5VC.js} +8 -8
  98. package/dist/{chunk-RKFNU5UA.js → chunk-QI72X67S.js} +104 -27
  99. package/dist/chunk-QKHZZFKH.js +98 -0
  100. package/dist/{chunk-5UG6EZI3.js → chunk-RDKX2PME.js} +4 -4
  101. package/dist/{chunk-B5ZTR6KZ.js → chunk-RL7LJYN4.js} +1 -1
  102. package/dist/{chunk-BE4I3UJ2.js → chunk-RQROVOV3.js} +15 -13
  103. package/dist/{chunk-TEHVMHOK.js → chunk-S34A7BSP.js} +3 -3
  104. package/dist/{chunk-4P6M2TTE.js → chunk-SJETVJHX.js} +2 -2
  105. package/dist/{chunk-OPC4DQD6.js → chunk-SJMNU4ZS.js} +2 -2
  106. package/dist/{chunk-2JSCCEKO.js → chunk-SLLG2G44.js} +2 -2
  107. package/dist/{chunk-EPYATQMG.js → chunk-SQAZN2V3.js} +42 -16
  108. package/dist/{chunk-E2NSPYLC.js → chunk-SQBT46OF.js} +5 -5
  109. package/dist/{chunk-WTZVSMQZ.js → chunk-TCUOGIL2.js} +5 -5
  110. package/dist/{chunk-RRZFRIJP.js → chunk-TIWPKCVO.js} +5 -5
  111. package/dist/{chunk-QLAGXTTV.js → chunk-UIU7MGZ3.js} +5 -1
  112. package/dist/{chunk-WLHX3MM5.js → chunk-V4XJWDHR.js} +21 -11
  113. package/dist/{chunk-PJ5H5B7A.js → chunk-VPWGADBG.js} +18 -18
  114. package/dist/{chunk-GEYX2NZ5.js → chunk-VWFCAK34.js} +6 -6
  115. package/dist/{chunk-44U2OUSM.js → chunk-W72LLZAV.js} +2 -2
  116. package/dist/{chunk-ORRNGQDV.js → chunk-WGRDABW7.js} +4 -4
  117. package/dist/{chunk-RNLAPBJL.js → chunk-XFLSL7BT.js} +2 -2
  118. package/dist/{chunk-2SXGG2IV.js → chunk-XJZEDCNT.js} +6 -6
  119. package/dist/{chunk-UB33F3YW.js → chunk-XLLEL3K7.js} +5 -5
  120. package/dist/{chunk-2GPGAE5W.js → chunk-XNIZBOFV.js} +15 -1
  121. package/dist/{chunk-WS4FOGLY.js → chunk-XNZWWDC3.js} +2 -2
  122. package/dist/{chunk-P7GTE4FX.js → chunk-XRECG65F.js} +2 -2
  123. package/dist/chunk-XTQ7MEJG.js +457 -0
  124. package/dist/{chunk-GEVQNST4.js → chunk-XZWSP67B.js} +2 -2
  125. package/dist/{chunk-OEMFEL26.js → chunk-Y3M2T5RO.js} +3 -3
  126. package/dist/{chunk-HP7KJ5O2.js → chunk-YPQOPFP7.js} +6 -6
  127. package/dist/{chunk-MEHBW2SP.js → chunk-YQYINEJI.js} +6 -6
  128. package/dist/{chunk-RXI7K4J5.js → chunk-ZF6CV4WZ.js} +1338 -217
  129. package/dist/{chunk-3XE4NRLF.js → chunk-ZKJU55MX.js} +4 -2
  130. package/dist/{chunk-526ABLHD.js → chunk-ZKQ63XZ5.js} +12 -35
  131. package/dist/{chunk-PAQVETLA.js → chunk-ZKVMDNAN.js} +5 -5
  132. package/dist/cli/index.js +47 -37
  133. package/dist/{clio-BPBAPZGA.js → clio-JUDCLNHC.js} +7 -7
  134. package/dist/clio-context-tools-FT672MNZ.js +136 -0
  135. package/dist/{code-nav-KBQ3RIFK.js → code-nav-7OVCTP2Z.js} +28 -26
  136. package/dist/{components-6DKAXWFN.js → components-OZXZMDWU.js} +5 -5
  137. package/dist/{config-FWL5JK2H.js → config-P3ZQVF63.js} +80 -75
  138. package/dist/{config-graph-ACDB26L2.js → config-graph-GKAOBAS5.js} +74 -70
  139. package/dist/{configure-ZIZ4YV62.js → configure-25LRYZJG.js} +45 -44
  140. package/dist/context-72VQV7JX.js +73 -0
  141. package/dist/{context-VIL5MFRH.js → context-COWRWXP3.js} +74 -70
  142. package/dist/{context-Z3GOBHDK.js → context-WB3D474G.js} +12 -12
  143. package/dist/{context-clear-ZPB3L7MN.js → context-clear-Y4LYMWC6.js} +70 -66
  144. package/dist/{context-working-set-2GLBVF7L.js → context-working-set-TMZYVC7A.js} +15 -14
  145. package/dist/data-tool-KMBWKKWR.js +2987 -0
  146. package/dist/{detail-VSBWYSGZ.js → detail-4GLROGY5.js} +71 -67
  147. package/dist/{dispatch-runner-EEEHGKX4.js → dispatch-runner-TR3LBP5P.js} +92 -88
  148. package/dist/{docs-VMMWFVHL.js → docs-ZK777W2G.js} +3 -3
  149. package/dist/{doctor-V5L4IQGP.js → doctor-WC4OV2OB.js} +61 -59
  150. package/dist/{eval-VJYJ2BV3.js → eval-FUNWJNUJ.js} +45 -45
  151. package/dist/{evals-J2H5V6DD.js → evals-L73EBHSU.js} +4 -4
  152. package/dist/{evidence-Y35YSXH6.js → evidence-AVJ2RTHX.js} +80 -76
  153. package/dist/{evidence-POWAEBEW.js → evidence-P4NZOAK7.js} +70 -66
  154. package/dist/{evidence-XCCCLS36.js → evidence-Y55WKYHH.js} +79 -75
  155. package/dist/{evolve-GPG72VB6.js → evolve-MAWKRYWF.js} +75 -71
  156. package/dist/{extensions-YIZ7W3DA.js → extensions-PYQH3H47.js} +8 -8
  157. package/dist/{fleet-2MDCQ2VK.js → fleet-M4H2QBWT.js} +84 -80
  158. package/dist/{fleet-W2AF3TOJ.js → fleet-ULBXXRDR.js} +123 -119
  159. package/dist/{fleet-commands-WS56G26H.js → fleet-commands-7NNC4JZU.js} +17 -16
  160. package/dist/{fleet-decisions-MYGZ3JW7.js → fleet-decisions-EHEY7KPU.js} +9 -9
  161. package/dist/{fleet-graph-ELTBXBAV.js → fleet-graph-LQ2AHZT3.js} +15 -15
  162. package/dist/{fleet-inspect-45IK73L4.js → fleet-inspect-5IGBIIYZ.js} +76 -72
  163. package/dist/{fleet-preflight-T5NCZKHE.js → fleet-preflight-UTTNOKMG.js} +7 -2
  164. package/dist/{fleet-validate-VG4JBLA4.js → fleet-validate-YGILJKA6.js} +20 -20
  165. package/dist/{fleet-verify-VTSABAYO.js → fleet-verify-AUWTCDKR.js} +70 -66
  166. package/dist/{fleet-view-XC7WMKSS.js → fleet-view-TGUFCY5A.js} +73 -69
  167. package/dist/{init-VTJNNTIP.js → init-GFN2Z7NF.js} +94 -90
  168. package/dist/{interop-IU6BNA7C.js → interop-EF5JUWWK.js} +21 -21
  169. package/dist/{inventory-QPQUTUUZ.js → inventory-I6VJDDYF.js} +73 -69
  170. package/dist/{library-Q3NWL5CM.js → library-3J5IO2OJ.js} +13 -13
  171. package/dist/{library-LF7DLU6S.js → library-IJTOFTDS.js} +16 -15
  172. package/dist/{library-HUTAS57T.js → library-Z3KZSHPE.js} +27 -27
  173. package/dist/{library-import-PPW4YUC5.js → library-import-IMKFLDHX.js} +21 -21
  174. package/dist/{library-inventory-DIRVFRZU.js → library-inventory-CQP5D6GU.js} +13 -13
  175. package/dist/{library-validation-XHUZ3INE.js → library-validation-33UTX7AI.js} +11 -11
  176. package/dist/mcp-5FWZKUS6.js +26 -0
  177. package/dist/{memory-Z2LSKNV6.js → memory-36CWN67Y.js} +75 -71
  178. package/dist/{models-3FTREYPY.js → models-KQ6PQJJQ.js} +49 -49
  179. package/dist/{monitor-HF2MQRB3.js → monitor-XX6ZD6KC.js} +83 -79
  180. package/dist/{orchestrator-UYPA6W4S.js → orchestrator-SK6HDAOP.js} +1337 -772
  181. package/dist/{panes-736XB73K.js → panes-L27QRXUH.js} +12 -12
  182. package/dist/{panes-C4P3PIWT.js → panes-LXZIWNOZ.js} +4 -4
  183. package/dist/{paths-JQ4QYIYB.js → paths-7DJDU4P4.js} +5 -5
  184. package/dist/{preload-XSLRYH3Y.js → preload-K2TDYI4Y.js} +70 -66
  185. package/dist/{reset-V7QSPZYE.js → reset-73VU3XNT.js} +10 -10
  186. package/dist/{resources-OJGDFHYT.js → resources-3BYJYVYL.js} +16 -16
  187. package/dist/{run-T354SMDW.js → run-AR7PY6GW.js} +132 -128
  188. package/dist/run-script-H2KUDIII.js +41 -0
  189. package/dist/{settings-MWZXO6RV.js → settings-3VMBMWID.js} +4 -4
  190. package/dist/{share-Y5ZKJPND.js → share-HVWH4FPF.js} +21 -21
  191. package/dist/{skills-4GLZC4LN.js → skills-5TYEY75Q.js} +22 -22
  192. package/dist/{skills-eval-L5T7GODM.js → skills-eval-CK3MD63Z.js} +96 -87
  193. package/dist/{skills-inventory-LASKXEZI.js → skills-inventory-KSFYG3I6.js} +16 -16
  194. package/dist/{slash-commands-OIMRU36D.js → slash-commands-DMVHML7P.js} +47 -44
  195. package/dist/{steer-KMAM2Y2C.js → steer-XCD6V3EW.js} +4 -4
  196. package/dist/{support-AWC3XKPX.js → support-JAZL6VBR.js} +7 -7
  197. package/dist/{system-CD75NYBU.js → system-3TDQRMZZ.js} +26 -26
  198. package/dist/{targets-VSZX2J2S.js → targets-EZKHAYRN.js} +66 -65
  199. package/dist/{tasks-AN567LYH.js → tasks-SNEFHWYW.js} +12 -12
  200. package/dist/{terminal-lease-6KTWNHVY.js → terminal-lease-BNLFA4OF.js} +8 -7
  201. package/dist/{tools-AGRK3V5J.js → tools-7IM6BDCE.js} +12 -12
  202. package/dist/{trace-P4MQZD33.js → trace-C3MBGD4S.js} +8 -8
  203. package/dist/{tui-primitives-A6MUW32V.js → tui-primitives-36BY2774.js} +2 -2
  204. package/dist/{uninstall-BRUTEPIC.js → uninstall-WWLOSZ42.js} +10 -10
  205. package/dist/{upgrade-SBCGHQGJ.js → upgrade-ETK2JNSJ.js} +37 -47
  206. package/dist/{usage-BIDVTO6V.js → usage-S2HOB7BZ.js} +93 -89
  207. package/dist/{verifiers-LTGCAMXS.js → verifiers-QDTEVH7R.js} +24 -22
  208. package/dist/{verify-OZU4LLNP.js → verify-SUKUK6XM.js} +15 -14
  209. package/dist/web/client/assets/{abnfDiagram-VCTEODGH-C5wfoHm3.js → abnfDiagram-VCTEODGH-BznNOe_I.js} +1 -1
  210. package/dist/web/client/assets/{arc-oH91sfLl.js → arc-Pry-7G1_.js} +1 -1
  211. package/dist/web/client/assets/architecture-7GRP2DOG-BQO9DL_y.js +1 -0
  212. package/dist/web/client/assets/architectureDiagram-5GKGNRK7-CKPbdvyx.js +36 -0
  213. package/dist/web/client/assets/{blockDiagram-I7D4REHJ-wi0_CYHL.js → blockDiagram-I7D4REHJ-prINbpbM.js} +1 -1
  214. package/dist/web/client/assets/{c4Diagram-7LVT6UL2-DV7NYc2W.js → c4Diagram-7LVT6UL2-DkVRKtyU.js} +1 -1
  215. package/dist/web/client/assets/channel-c4EeUUqA.js +1 -0
  216. package/dist/web/client/assets/{chunk-4HAMMTFA-Bhsegh3F.js → chunk-4HAMMTFA-CV0Z1ApC.js} +1 -1
  217. package/dist/web/client/assets/{chunk-75Z2AOVW-RQCckcQG.js → chunk-75Z2AOVW-D34Nohxq.js} +1 -1
  218. package/dist/web/client/assets/chunk-DU6HZSFF-Das_cS-O.js +125 -0
  219. package/dist/web/client/assets/{chunk-F27PBJKO-BcNqv2x1.js → chunk-F27PBJKO-CmRojxkG.js} +1 -1
  220. package/dist/web/client/assets/{chunk-GMAD6QVW-Bq8JWiZT.js → chunk-GMAD6QVW-ClYZmc73.js} +1 -1
  221. package/dist/web/client/assets/{chunk-GVQU2GXP-DbchrAeJ.js → chunk-GVQU2GXP-B2BiHFt-.js} +1 -1
  222. package/dist/web/client/assets/{chunk-IMKFNOWR-DrpvjocK.js → chunk-IMKFNOWR-BGApZ8nP.js} +1 -1
  223. package/dist/web/client/assets/{chunk-L3NEJ4N5-DHLmTnCe.js → chunk-L3NEJ4N5-DIzCgpkY.js} +1 -1
  224. package/dist/web/client/assets/{chunk-OSK3NFVY-CsRbtN9n.js → chunk-OSK3NFVY-BPT-yePv.js} +1 -1
  225. package/dist/web/client/assets/{chunk-P2QGCYS3-aqPbxoMh.js → chunk-P2QGCYS3-BC1WTc2t.js} +1 -1
  226. package/dist/web/client/assets/{chunk-POPQ4Y6H-Dl5vw0h0.js → chunk-POPQ4Y6H-BSjzBmZU.js} +1 -1
  227. package/dist/web/client/assets/{chunk-PWAF6VOD-D7OBRSdO.js → chunk-PWAF6VOD-BIjLs86Z.js} +1 -1
  228. package/dist/web/client/assets/{chunk-SHT3W25Y-CdKCIwuB.js → chunk-SHT3W25Y-CduDz2cm.js} +1 -1
  229. package/dist/web/client/assets/{chunk-SVP7TREG-B94Nu_1-.js → chunk-SVP7TREG-XUn4pPAP.js} +1 -1
  230. package/dist/web/client/assets/{chunk-TICWLB2K-jjRQI_hk.js → chunk-TICWLB2K-DcBy2DKy.js} +1 -1
  231. package/dist/web/client/assets/{chunk-XXDRQBXY-azkbKE37.js → chunk-XXDRQBXY-DqAYeljN.js} +1 -1
  232. package/dist/web/client/assets/classDiagram-ZZMXUADV-C0HR7YKN.js +1 -0
  233. package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-C0HR7YKN.js +1 -0
  234. package/dist/web/client/assets/cose-bilkent-JH36ORCC-CVh1icwb.js +1 -0
  235. package/dist/web/client/assets/{cynefin-OW5HDTMX--i9RDU5f.js → cynefin-OW5HDTMX-BecPbyM6.js} +1 -1
  236. package/dist/web/client/assets/{cynefinDiagram-5FMLGOSQ-cRcvyBdp.js → cynefinDiagram-5FMLGOSQ-BzMzFwyT.js} +1 -1
  237. package/dist/web/client/assets/{dagre-GXQ25YYZ-C9mZmAPe.js → dagre-GXQ25YYZ-CAWJmRMG.js} +1 -1
  238. package/dist/web/client/assets/{diagram-S7CK7UJ4-Oj_zlLDY.js → diagram-S7CK7UJ4--lp0ALmn.js} +1 -1
  239. package/dist/web/client/assets/{diagram-UQ7AKVKN-BWKbbfcR.js → diagram-UQ7AKVKN-gKUnsjcj.js} +1 -1
  240. package/dist/web/client/assets/{diagram-VSXAHHWV-C3N3f7DO.js → diagram-VSXAHHWV-BoN5D1Gh.js} +1 -1
  241. package/dist/web/client/assets/{diagram-VX7I27RA-CtDKDAWe.js → diagram-VX7I27RA-BMtuswQ6.js} +1 -1
  242. package/dist/web/client/assets/{diagram-Z3DM3KII-B8bkBRCz.js → diagram-Z3DM3KII-DtU8LXrA.js} +1 -1
  243. package/dist/web/client/assets/dist-v5Q1xZ2K.js +1 -0
  244. package/dist/web/client/assets/{ebnfDiagram-PWID7BFC-CskW-Whx.js → ebnfDiagram-PWID7BFC-DDcnv9BH.js} +1 -1
  245. package/dist/web/client/assets/{erDiagram-RLTQ6QDP-C-83cgCW.js → erDiagram-RLTQ6QDP-DvRb4iDL.js} +1 -1
  246. package/dist/web/client/assets/eventmodeling-NTZA5JFV-01h4SbTc.js +1 -0
  247. package/dist/web/client/assets/flowDiagram-HODETNUW-Bll_YZ6T.js +1 -0
  248. package/dist/web/client/assets/framework-YGoR34M4.js +9 -0
  249. package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-DdFZ9hvH.js +292 -0
  250. package/dist/web/client/assets/{gitGraph-4MIJSDKK-B40cQtBE.js → gitGraph-4MIJSDKK-DjD_AAMj.js} +1 -1
  251. package/dist/web/client/assets/{gitGraphDiagram-WWUBYQGX-CH-7P7Di.js → gitGraphDiagram-WWUBYQGX-CDyN9n2u.js} +1 -1
  252. package/dist/web/client/assets/index-CVcy0FAn.js +75 -0
  253. package/dist/web/client/assets/{info-A6RAGUB7-eCCE9D_Q.js → info-A6RAGUB7-C_XK8Hq0.js} +1 -1
  254. package/dist/web/client/assets/{infoDiagram-27XIBGKW-DRnvqMjM.js → infoDiagram-27XIBGKW-DIe4tJ1i.js} +1 -1
  255. package/dist/web/client/assets/{ishikawaDiagram-5VMMS53U-DBA_55wp.js → ishikawaDiagram-5VMMS53U-CVl5unKI.js} +1 -1
  256. package/dist/web/client/assets/{journeyDiagram-3NMN7TZE-C-ewpNl7.js → journeyDiagram-3NMN7TZE-CPEB1Vt8.js} +1 -1
  257. package/dist/web/client/assets/{kanban-definition-UXKFOSKX-B1taGsu0.js → kanban-definition-UXKFOSKX-j-9WXjYQ.js} +1 -1
  258. package/dist/web/client/assets/{line-lZ0kyxDI.js → line-BIDAcEtX.js} +1 -1
  259. package/dist/web/client/assets/{linear-DIc8FgZj.js → linear-SzVmGSw4.js} +1 -1
  260. package/dist/web/client/assets/{mermaid-parser.core-SXolxpXw.js → mermaid-parser.core-Ux4vssh0.js} +3 -3
  261. package/dist/web/client/assets/{mermaid.core-DXgQtkNg.js → mermaid.core-CDuwVKeh.js} +4 -4
  262. package/dist/web/client/assets/{mindmap-definition-YA3MSWOX-DXJas9K7.js → mindmap-definition-YA3MSWOX-5MlQEeQ6.js} +1 -1
  263. package/dist/web/client/assets/{packet-AYTQ26CC-OqVl_07o.js → packet-AYTQ26CC-DRO66c9Q.js} +1 -1
  264. package/dist/web/client/assets/{pegDiagram-XKGWAZYB-CPE_zdfN.js → pegDiagram-XKGWAZYB-BakZnSjM.js} +1 -1
  265. package/dist/web/client/assets/{pie-WAS4IAKB-DAxnMBLe.js → pie-WAS4IAKB-BEzcmhz8.js} +1 -1
  266. package/dist/web/client/assets/{pieDiagram-E7YTZNPT-Uwjpufxv.js → pieDiagram-E7YTZNPT-DpmqgoPt.js} +1 -1
  267. package/dist/web/client/assets/prism-core-BtsZdCS6.js +1 -0
  268. package/dist/web/client/assets/{quadrantDiagram-AXDQQJYC-Bjs4yjgs.js → quadrantDiagram-AXDQQJYC-DuMPwwV2.js} +1 -1
  269. package/dist/web/client/assets/{radar-RG4KPBEZ-CuCKjHM3.js → radar-RG4KPBEZ-Djm3oXl5.js} +1 -1
  270. package/dist/web/client/assets/{railroad-74A4TZTK-CnQK-Cc1.js → railroad-74A4TZTK-Cpvkwsao.js} +1 -1
  271. package/dist/web/client/assets/railroad-abnf-HS5TGJTU-CpRQ3ruG.js +1 -0
  272. package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-1Rm5a5eJ.js +1 -0
  273. package/dist/web/client/assets/railroad-peg-WCYAUIDC-C8344cTh.js +1 -0
  274. package/dist/web/client/assets/{railroadDiagram-O6MQD6OU-BDDIPNLL.js → railroadDiagram-O6MQD6OU-CgMS4B6R.js} +1 -1
  275. package/dist/web/client/assets/{requirementDiagram-BXWQKSXE-B5Ydyxc1.js → requirementDiagram-BXWQKSXE-CX5eoNdN.js} +1 -1
  276. package/dist/web/client/assets/rolldown-runtime-hePW80VL.js +1 -0
  277. package/dist/web/client/assets/{sankeyDiagram-P5KCCOFB-Bw2Qym75.js → sankeyDiagram-P5KCCOFB-CODBX2N3.js} +1 -1
  278. package/dist/web/client/assets/{sequenceDiagram-WJ2MYXX4-BZf36nO0.js → sequenceDiagram-WJ2MYXX4-eUhhF8OR.js} +1 -1
  279. package/dist/web/client/assets/src-B6xuSHsQ.js +1 -0
  280. package/dist/web/client/assets/{stateDiagram-D77RDMKH-DnH6JRkp.js → stateDiagram-D77RDMKH-vR6l0NC2.js} +1 -1
  281. package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-BYUm8jLY.js +1 -0
  282. package/dist/web/client/assets/{swimlanes-42K2YHIH-D9PZmtZg.js → swimlanes-42K2YHIH-v9Tw_zX7.js} +1 -1
  283. package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-B2jdCvhD.js +8 -0
  284. package/dist/web/client/assets/{timeline-definition-24CTP7MA-CrkZZBo7.js → timeline-definition-24CTP7MA-DxianbhU.js} +1 -1
  285. package/dist/web/client/assets/{treeView-Q6P3EWNA-C9zDShoC.js → treeView-Q6P3EWNA-DLxnZb9R.js} +1 -1
  286. package/dist/web/client/assets/{treemap-WGGIJYW6-B-plj9yK.js → treemap-WGGIJYW6-I7UnZ6xJ.js} +1 -1
  287. package/dist/web/client/assets/{vennDiagram-4TSXK5OY-VeOdaphN.js → vennDiagram-4TSXK5OY-Ar7M8Mrj.js} +1 -1
  288. package/dist/web/client/assets/{wardley-WFR3VGLG-Wl1P_m6L.js → wardley-WFR3VGLG-B8ZSHeDu.js} +1 -1
  289. package/dist/web/client/assets/{wardleyDiagram-VM6X3IG4-B85-R9t2.js → wardleyDiagram-VM6X3IG4-Qks2FmIn.js} +1 -1
  290. package/dist/web/client/assets/{xychartDiagram-S5SC5T6Z-BrD8OW8m.js → xychartDiagram-S5SC5T6Z-BBBjRtiE.js} +1 -1
  291. package/dist/web/client/index.html +3 -1
  292. package/dist/web/reads-worker.js +17 -17
  293. package/dist/web/server.js +25 -25
  294. package/dist/{web-EU6ATJWA.js → web-EMGUGGEI.js} +3 -3
  295. package/dist/{web-fetch-U22Q7HV4.js → web-fetch-6BRRVQON.js} +22 -5
  296. package/dist/{wiki-generate-LZRLFG6I.js → wiki-generate-XHSJTDOP.js} +104 -100
  297. package/dist/{with-panes-X5CZOGML.js → with-panes-Z6BTEHMZ.js} +11 -11
  298. package/dist/worker/entry.js +101 -87
  299. package/docs/README.md +1 -1
  300. package/docs/architecture/artifact-placement.md +12 -1
  301. package/docs/architecture/library.md +1 -1
  302. package/docs/architecture/prompt-envelope-and-tools.md +37 -27
  303. package/docs/architecture/safety-model.md +19 -6
  304. package/docs/architecture/session-lifecycle.md +10 -4
  305. package/docs/architecture/tui-design.md +37 -14
  306. package/docs/guide/commands-and-modes.md +39 -19
  307. package/docs/guide/configuration-and-targets.md +7 -5
  308. package/docs/guide/configuration-reference.md +116 -13
  309. package/docs/guide/environment-variables.md +2 -5
  310. package/docs/guide/fleet-dispatch.md +3 -2
  311. package/docs/guide/glossary.md +1 -1
  312. package/docs/guide/installation-and-lifecycle.md +2 -2
  313. package/docs/guide/resource-library.md +1 -1
  314. package/docs/guide/tool-usage.md +166 -64
  315. package/docs/guide/troubleshooting.md +1 -1
  316. package/docs/process/documentation-guide.md +1 -0
  317. package/docs/process/fleet-demo-runbook.md +6 -6
  318. package/docs/process/scientific-validation.md +22 -2
  319. package/docs/process/tool-audit-v0.4.9.md +357 -0
  320. package/package.json +1 -1
  321. package/src/cli/argv.ts +31 -0
  322. package/src/cli/clio.ts +17 -13
  323. package/src/cli/config.ts +4 -0
  324. package/src/cli/doctor-panes.ts +1 -1
  325. package/src/cli/doctor.ts +3 -1
  326. package/src/cli/index.ts +14 -1
  327. package/src/cli/mcp.ts +106 -0
  328. package/src/cli/skills-eval.ts +8 -2
  329. package/src/cli/upgrade.ts +34 -38
  330. package/src/cli/verifiers.ts +1 -1
  331. package/src/core/bash-exec.ts +27 -4
  332. package/src/core/config.ts +2 -1
  333. package/src/core/defaults.ts +10 -1
  334. package/src/core/event-bus.ts +1 -1
  335. package/src/core/run-records.ts +438 -0
  336. package/src/core/safe-exec.ts +506 -56
  337. package/src/core/skill-activation.ts +5 -3
  338. package/src/core/termination.ts +3 -3
  339. package/src/core/tool-names.ts +33 -12
  340. package/src/domains/context/clio-md.ts +1 -1
  341. package/src/domains/context/worker/pressure.ts +6 -2
  342. package/src/domains/context/working-set/path-index.ts +7 -2
  343. package/src/domains/dispatch/code-step.ts +7 -2
  344. package/src/domains/dispatch/contract.ts +7 -0
  345. package/src/domains/dispatch/execution-role.ts +3 -3
  346. package/src/domains/dispatch/execution-scheduler.ts +204 -79
  347. package/src/domains/dispatch/extension.ts +131 -14
  348. package/src/domains/dispatch/fleet-preflight.ts +18 -3
  349. package/src/domains/dispatch/fleet-run.ts +1 -0
  350. package/src/domains/dispatch/gate-decisions.ts +3 -3
  351. package/src/domains/dispatch/heartbeat.ts +1 -1
  352. package/src/domains/dispatch/host-verification.ts +16 -14
  353. package/src/domains/dispatch/receipt-findings.ts +3 -4
  354. package/src/domains/dispatch/reservation-store.ts +7 -9
  355. package/src/domains/dispatch/route-facts.ts +1 -1
  356. package/src/domains/dispatch/state.ts +3 -3
  357. package/src/domains/dispatch/types.ts +1 -1
  358. package/src/domains/evidence/build.ts +35 -7
  359. package/src/domains/gateway/mcp/client.ts +923 -0
  360. package/src/domains/gateway/mcp/config.ts +456 -0
  361. package/src/domains/gateway/mcp/index.ts +88 -0
  362. package/src/domains/gateway/mcp/protocol.ts +273 -0
  363. package/src/domains/gateway/mcp/trust.ts +263 -0
  364. package/src/domains/lifecycle/doctor.ts +17 -3
  365. package/src/domains/mux/contract.ts +5 -9
  366. package/src/domains/mux/detect.ts +1 -1
  367. package/src/domains/mux/extension.ts +1 -1
  368. package/src/domains/mux/protocol.ts +5 -7
  369. package/src/domains/mux/socket-client.ts +3 -3
  370. package/src/domains/observability/accountability.ts +2 -2
  371. package/src/domains/observability/contract.ts +7 -3
  372. package/src/domains/observability/evidence-index.ts +2 -2
  373. package/src/domains/observability/projection.ts +10 -0
  374. package/src/domains/prompts/compiler.ts +41 -23
  375. package/src/domains/prompts/fragments/identity/docs-routing.md +2 -2
  376. package/src/domains/prompts/fragments/operating/skills.md +12 -10
  377. package/src/domains/providers/index.ts +5 -1
  378. package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +42 -10
  379. package/src/domains/providers/probe/http.ts +44 -59
  380. package/src/domains/providers/probe/reasoning.ts +2 -0
  381. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +20 -31
  382. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +9 -4
  383. package/src/domains/safety/action-classifier.ts +17 -1
  384. package/src/domains/safety/call-target.ts +14 -0
  385. package/src/domains/safety/contract.ts +1 -1
  386. package/src/domains/safety/finish-contract.ts +9 -3
  387. package/src/domains/safety/loop-detector.ts +1 -1
  388. package/src/domains/safety/policy-engine.ts +7 -0
  389. package/src/domains/safety/protected-artifacts.ts +3 -4
  390. package/src/domains/safety/rejection-feedback.ts +1 -1
  391. package/src/domains/safety/scope.ts +2 -3
  392. package/src/domains/safety/validation-contract.ts +3 -2
  393. package/src/domains/scheduling/budget.ts +5 -3
  394. package/src/domains/scheduling/contract.ts +2 -1
  395. package/src/domains/scheduling/extension.ts +3 -3
  396. package/src/domains/session/compaction/branch-summary.ts +1 -1
  397. package/src/domains/session/compaction/compact.ts +25 -2
  398. package/src/domains/session/compaction/cut-point.ts +1 -1
  399. package/src/domains/session/compaction/tokens.ts +5 -10
  400. package/src/domains/session/contract.ts +1 -1
  401. package/src/domains/session/cwd-fallback.ts +2 -2
  402. package/src/domains/session/handoff.ts +5 -1
  403. package/src/domains/session/history.ts +6 -0
  404. package/src/domains/session/manager.ts +14 -7
  405. package/src/domains/session/retry.ts +2 -1
  406. package/src/domains/session/session-artifacts.ts +12 -7
  407. package/src/domains/session/task-board.ts +2 -3
  408. package/src/engine/apis/openai-completions.ts +8 -0
  409. package/src/engine/loop-guard.ts +7 -0
  410. package/src/engine/provider-error-body.ts +65 -0
  411. package/src/engine/session.ts +118 -29
  412. package/src/engine/worker-runtime.ts +3 -0
  413. package/src/entry/boot-options.ts +2 -0
  414. package/src/entry/orchestrator.ts +18 -2
  415. package/src/interactive/chat-loop-policy.ts +1 -0
  416. package/src/interactive/chat-loop.ts +8 -4
  417. package/src/interactive/chat-panel.ts +23 -9
  418. package/src/interactive/chat-renderer.ts +33 -11
  419. package/src/interactive/clio-editor.ts +13 -5
  420. package/src/interactive/dispatch-board.ts +70 -30
  421. package/src/interactive/editor-submit.ts +30 -25
  422. package/src/interactive/footer/widgets.ts +12 -9
  423. package/src/interactive/interactive-presentation.ts +2 -3
  424. package/src/interactive/mux-bridge.ts +3 -7
  425. package/src/interactive/overlay-general-openers.ts +14 -7
  426. package/src/interactive/overlays/cwd-fallback.ts +1 -1
  427. package/src/interactive/overlays/library-model.ts +114 -35
  428. package/src/interactive/overlays/library.ts +52 -5
  429. package/src/interactive/overlays/list-overlay.ts +4 -1
  430. package/src/interactive/overlays/session-selector.ts +28 -23
  431. package/src/interactive/overlays/settings.ts +20 -1
  432. package/src/interactive/overlays/tree-selector.ts +47 -10
  433. package/src/interactive/panes-runtime.ts +1 -1
  434. package/src/interactive/renderers/compaction-summary.ts +1 -1
  435. package/src/interactive/renderers/provider-error.ts +118 -0
  436. package/src/interactive/renderers/retry-status.ts +59 -23
  437. package/src/interactive/renderers/tool-execution.ts +67 -7
  438. package/src/interactive/renderers/worker-answer.ts +198 -0
  439. package/src/interactive/renderers/worker-entry.ts +57 -163
  440. package/src/interactive/slash-commands.ts +26 -1
  441. package/src/interactive/slash-spec.ts +2 -2
  442. package/src/interactive/theme/labels.ts +66 -30
  443. package/src/interactive/turn-persistence.ts +6 -1
  444. package/src/interactive/turn-recovery.ts +2 -1
  445. package/src/interactive/turn-runtime.ts +22 -5
  446. package/src/interactive/view/artifacts.ts +3 -2
  447. package/src/interactive/view/view-overlay.ts +96 -20
  448. package/src/tools/agent-tools.ts +21 -7
  449. package/src/tools/artifact.ts +16 -8
  450. package/src/tools/bash.ts +90 -11
  451. package/src/tools/bootstrap.ts +42 -4
  452. package/src/tools/builtin-tool-catalog.ts +72 -7
  453. package/src/tools/context/index.ts +27 -31
  454. package/src/tools/context/library.ts +3 -1
  455. package/src/tools/context/surface.ts +12 -26
  456. package/src/tools/core-bootstrap.ts +72 -1
  457. package/src/tools/data/csv.ts +1189 -0
  458. package/src/tools/data/index.ts +308 -0
  459. package/src/tools/data/json.ts +1799 -0
  460. package/src/tools/data/jsonl.ts +561 -0
  461. package/src/tools/data/shared.ts +452 -0
  462. package/src/tools/edit-diff.ts +0 -7
  463. package/src/tools/edit.ts +115 -18
  464. package/src/tools/file-mutation-queue.ts +114 -4
  465. package/src/tools/find.ts +108 -29
  466. package/src/tools/gateway/caps.ts +11 -0
  467. package/src/tools/gateway/clio-context-surface.ts +41 -0
  468. package/src/tools/gateway/clio-context-tools.ts +77 -0
  469. package/src/tools/gateway/data-surface.ts +138 -0
  470. package/src/tools/gateway/data-tool.ts +201 -0
  471. package/src/tools/gateway/index.ts +342 -0
  472. package/src/tools/gateway/mcp-capabilities.ts +469 -0
  473. package/src/tools/grep.ts +88 -33
  474. package/src/tools/harness-extensions.ts +3 -0
  475. package/src/tools/ignore-policy.ts +7 -5
  476. package/src/tools/ls.ts +111 -20
  477. package/src/tools/policy.ts +35 -13
  478. package/src/tools/presentation.ts +6 -0
  479. package/src/tools/read.ts +634 -156
  480. package/src/tools/registry.ts +94 -6
  481. package/src/tools/run-script.ts +997 -0
  482. package/src/tools/spawn-hygiene.ts +157 -5
  483. package/src/tools/surface.ts +163 -0
  484. package/src/tools/verify/authoring.ts +8 -3
  485. package/src/tools/verify/catalog.ts +14 -1
  486. package/src/tools/verify/numeric.ts +367 -59
  487. package/src/tools/verify/perf.ts +171 -9
  488. package/src/tools/verify/scripts.ts +178 -26
  489. package/src/tools/web-fetch-surface.ts +22 -0
  490. package/src/tools/web-fetch.ts +26 -1
  491. package/src/tools/write.ts +45 -19
  492. package/dist/chunk-B6UM3OZC.js +0 -15
  493. package/dist/chunk-GJ24ODAX.js +0 -196
  494. package/dist/chunk-LZCCBLRC.js +0 -57
  495. package/dist/web/client/assets/architecture-7GRP2DOG-EGozsYEO.js +0 -1
  496. package/dist/web/client/assets/architectureDiagram-5GKGNRK7-z9FokbJl.js +0 -36
  497. package/dist/web/client/assets/channel-CiUWbHN9.js +0 -1
  498. package/dist/web/client/assets/chunk-DU6HZSFF-C5USiOAy.js +0 -125
  499. package/dist/web/client/assets/classDiagram-ZZMXUADV-CMODalmo.js +0 -1
  500. package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-CMODalmo.js +0 -1
  501. package/dist/web/client/assets/cose-bilkent-JH36ORCC-RbQL23qS.js +0 -1
  502. package/dist/web/client/assets/dist-D0_q-A2b.js +0 -1
  503. package/dist/web/client/assets/eventmodeling-NTZA5JFV-DjVq8wKU.js +0 -1
  504. package/dist/web/client/assets/flowDiagram-HODETNUW-BUiCBGXt.js +0 -1
  505. package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-B2lb8lvF.js +0 -292
  506. package/dist/web/client/assets/index-FSIC94pi.js +0 -83
  507. package/dist/web/client/assets/prism-core-BngLtbUd.js +0 -1
  508. package/dist/web/client/assets/railroad-abnf-HS5TGJTU-BcW01NZG.js +0 -1
  509. package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-B7YCEDDd.js +0 -1
  510. package/dist/web/client/assets/railroad-peg-WCYAUIDC-DjNZbSTZ.js +0 -1
  511. package/dist/web/client/assets/src-yeptRXpt.js +0 -1
  512. package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-C7QtHeK4.js +0 -1
  513. package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-CBZlPFky.js +0 -8
@@ -0,0 +1,452 @@
1
+ import { createReadStream, statSync } from "node:fs";
2
+
3
+ /**
4
+ * Shared substrate for the structured-data readers (csv.ts, json.ts,
5
+ * jsonl.ts): the fatal UTF-8 chunk decoder, the text stream with its byte
6
+ * accounting, the typed refusals every reader returns instead of a guess, and
7
+ * the cell classification the CSV and JSONL inspectors both use.
8
+ *
9
+ * Every reader streams. Nothing in this directory reads a data file whole,
10
+ * and every result says how it was produced (`DataViewFlags`) so a sampled
11
+ * scan can never pass for the complete dataset.
12
+ */
13
+
14
+ export const DATA_FORMATS = ["csv", "tsv", "json", "jsonl"] as const;
15
+ export type DataFormat = (typeof DATA_FORMATS)[number];
16
+
17
+ export function isDataFormat(value: unknown): value is DataFormat {
18
+ return typeof value === "string" && (DATA_FORMATS as ReadonlyArray<string>).includes(value);
19
+ }
20
+
21
+ /**
22
+ * How a result was produced. `exact` means every reported figure and every
23
+ * selected value covers the whole file verbatim; `sampled` means scanning
24
+ * stopped before the end, so counts are lower bounds and `rowCount` is null;
25
+ * `exact: false` with `sampled: false` means the scan was complete but a
26
+ * selected value was cut to a budget, with a `$summary` or `$truncated`
27
+ * placeholder marking each cut. Inspection samples are previews and are
28
+ * exempt: a placeholder inside a sample is noted, and `exact` still speaks
29
+ * for the counts. `converted` means a value was changed from its source text
30
+ * (the readers never set it: inspection classifies and selection returns
31
+ * source text or parsed JSON with precision preserved).
32
+ */
33
+ export interface DataViewFlags {
34
+ exact: boolean;
35
+ sampled: boolean;
36
+ converted: boolean;
37
+ }
38
+
39
+ export function exactView(): DataViewFlags {
40
+ return { exact: true, sampled: false, converted: false };
41
+ }
42
+
43
+ export function sampledView(): DataViewFlags {
44
+ return { exact: false, sampled: true, converted: false };
45
+ }
46
+
47
+ /** The scan was complete, but a returned value was cut to a budget. */
48
+ export function cutView(): DataViewFlags {
49
+ return { exact: false, sampled: false, converted: false };
50
+ }
51
+
52
+ export type DataRefusalReason =
53
+ | "not-found"
54
+ | "not-a-file"
55
+ | "read-error"
56
+ | "invalid-utf8"
57
+ | "binary"
58
+ | "unsupported-format"
59
+ | "aborted"
60
+ | "invalid-json"
61
+ | "nesting-too-deep"
62
+ | "invalid-argument"
63
+ | "pointer-not-found"
64
+ | "selection-too-large"
65
+ | "unknown-column";
66
+
67
+ /**
68
+ * A typed refusal. The readers return one of these instead of interpreting
69
+ * bytes they cannot honestly read: an invalid UTF-8 sequence names its byte
70
+ * offset, a binary file says so, an unsupported format names the supported
71
+ * ones, and a JSON syntax error names line, column, and byte offset.
72
+ */
73
+ export interface DataRefusal {
74
+ ok: false;
75
+ reason: DataRefusalReason;
76
+ message: string;
77
+ path?: string;
78
+ byteOffset?: number;
79
+ line?: number;
80
+ column?: number;
81
+ supported?: ReadonlyArray<string>;
82
+ }
83
+
84
+ export class DataRefusalError extends Error {
85
+ readonly refusal: DataRefusal;
86
+ constructor(refusal: DataRefusal) {
87
+ super(refusal.message);
88
+ this.name = "DataRefusalError";
89
+ this.refusal = refusal;
90
+ }
91
+ }
92
+
93
+ export function refusal(
94
+ reason: DataRefusalReason,
95
+ message: string,
96
+ extra: Omit<DataRefusal, "ok" | "reason" | "message"> = {},
97
+ ): DataRefusal {
98
+ return { ok: false, reason, message, ...extra };
99
+ }
100
+
101
+ export function isDataRefusal(value: unknown): value is DataRefusal {
102
+ return (
103
+ typeof value === "object" &&
104
+ value !== null &&
105
+ (value as { ok?: unknown }).ok === false &&
106
+ typeof (value as { reason?: unknown }).reason === "string"
107
+ );
108
+ }
109
+
110
+ /** Convert whatever a reader threw into the refusal it stands for. */
111
+ export function refusalFromError(error: unknown, path: string, signal?: AbortSignal | undefined): DataRefusal {
112
+ if (error instanceof DataRefusalError) return { ...error.refusal, path };
113
+ if (signal?.aborted) return refusal("aborted", "aborted before the scan finished", { path });
114
+ const code = (error as NodeJS.ErrnoException | undefined)?.code;
115
+ if (code === "ENOENT") return refusal("not-found", `no file at ${path}`, { path });
116
+ if (code === "EISDIR") return refusal("not-a-file", `${path} is a directory, not a data file`, { path });
117
+ const message = error instanceof Error ? error.message : String(error);
118
+ return refusal("read-error", `cannot read ${path}: ${message}`, { path });
119
+ }
120
+
121
+ function abortedRefusal(path: string): DataRefusal {
122
+ return refusal("aborted", "aborted before the scan finished", { path });
123
+ }
124
+
125
+ export function throwIfAborted(signal: AbortSignal | undefined, path: string): void {
126
+ if (signal?.aborted) throw new DataRefusalError(abortedRefusal(path));
127
+ }
128
+
129
+ /** Size and regular-file check, as a refusal when the path cannot be a data file. */
130
+ export function statDataFile(path: string): { size: number } | DataRefusal {
131
+ try {
132
+ const stat = statSync(path);
133
+ if (!stat.isFile()) return refusal("not-a-file", `${path} is not a regular file`, { path });
134
+ return { size: stat.size };
135
+ } catch (error) {
136
+ return refusalFromError(error, path);
137
+ }
138
+ }
139
+
140
+ // Well-formed UTF-8 byte sequences (Unicode 15, table 3-7). The decoder
141
+ // validates every sequence itself so an invalid byte is reported at its exact
142
+ // offset instead of surfacing as a silent U+FFFD from Buffer.toString.
143
+ const UTF8_LEAD_MIN = 0xc2;
144
+
145
+ /**
146
+ * Incremental fatal UTF-8 decoder. `push` validates and decodes every complete
147
+ * sequence in the chunk, carries an incomplete trailing sequence to the next
148
+ * push, and throws an `invalid-utf8` refusal naming the absolute byte offset
149
+ * where the first ill-formed sequence starts. `end` rejects a dangling partial
150
+ * sequence.
151
+ */
152
+ export class Utf8StreamDecoder {
153
+ private pending: Buffer | null = null;
154
+ /** Absolute byte offset of the first byte not yet decoded (the pending start). */
155
+ private offset = 0;
156
+
157
+ /** Absolute byte offset of the first byte the next decoded text will begin at. */
158
+ get position(): number {
159
+ return this.offset;
160
+ }
161
+
162
+ push(chunk: Buffer): string {
163
+ const buffer = this.pending === null ? chunk : Buffer.concat([this.pending, chunk]);
164
+ const length = buffer.length;
165
+ let index = 0;
166
+ while (index < length) {
167
+ const lead = buffer[index] as number;
168
+ if (lead < 0x80) {
169
+ index += 1;
170
+ continue;
171
+ }
172
+ let need: number;
173
+ let secondMin = 0x80;
174
+ let secondMax = 0xbf;
175
+ if (lead >= UTF8_LEAD_MIN && lead <= 0xdf) need = 2;
176
+ else if (lead === 0xe0) {
177
+ need = 3;
178
+ secondMin = 0xa0;
179
+ } else if (lead >= 0xe1 && lead <= 0xec) need = 3;
180
+ else if (lead === 0xed) {
181
+ need = 3;
182
+ secondMax = 0x9f;
183
+ } else if (lead >= 0xee && lead <= 0xef) need = 3;
184
+ else if (lead === 0xf0) {
185
+ need = 4;
186
+ secondMin = 0x90;
187
+ } else if (lead >= 0xf1 && lead <= 0xf3) need = 4;
188
+ else if (lead === 0xf4) {
189
+ need = 4;
190
+ secondMax = 0x8f;
191
+ } else {
192
+ throw this.invalid(index);
193
+ }
194
+ if (index + need > length) {
195
+ // Incomplete at the chunk edge: validate what is present, carry the rest.
196
+ const second = buffer[index + 1];
197
+ if (second !== undefined && (second < secondMin || second > secondMax)) throw this.invalid(index);
198
+ for (let k = 2; index + k < length; k += 1) {
199
+ const byte = buffer[index + k] as number;
200
+ if (byte < 0x80 || byte > 0xbf) throw this.invalid(index);
201
+ }
202
+ break;
203
+ }
204
+ const second = buffer[index + 1] as number;
205
+ if (second < secondMin || second > secondMax) throw this.invalid(index);
206
+ for (let k = 2; k < need; k += 1) {
207
+ const byte = buffer[index + k] as number;
208
+ if (byte < 0x80 || byte > 0xbf) throw this.invalid(index);
209
+ }
210
+ index += need;
211
+ }
212
+ const text = buffer.toString("utf8", 0, index);
213
+ // Copy the carried tail: the caller may reuse its chunk buffer.
214
+ this.pending = index < length ? Buffer.from(buffer.subarray(index)) : null;
215
+ this.offset += index;
216
+ return text;
217
+ }
218
+
219
+ end(): void {
220
+ if (this.pending !== null) throw this.invalid(0);
221
+ }
222
+
223
+ private invalid(relativeIndex: number): DataRefusalError {
224
+ const byteOffset = this.offset + relativeIndex;
225
+ return new DataRefusalError(
226
+ refusal(
227
+ "invalid-utf8",
228
+ `invalid UTF-8 sequence starting at byte offset ${byteOffset}; this is not a UTF-8 text file`,
229
+ {
230
+ byteOffset,
231
+ },
232
+ ),
233
+ );
234
+ }
235
+ }
236
+
237
+ export interface TextChunk {
238
+ text: string;
239
+ /** Absolute byte offset of the first byte of `text` in the file. */
240
+ byteOffset: number;
241
+ }
242
+
243
+ export interface TextStreamStats {
244
+ /** Bytes read from disk so far, including a stripped byte-order mark. */
245
+ bytesRead: number;
246
+ bom: boolean;
247
+ }
248
+
249
+ export interface TextStreamOptions {
250
+ signal?: AbortSignal | undefined;
251
+ stats: TextStreamStats;
252
+ highWaterMark?: number;
253
+ }
254
+
255
+ const BINARY_SNIFF_BYTES = 8192;
256
+ const DEFAULT_HIGH_WATER_MARK = 64 * 1024;
257
+
258
+ /**
259
+ * Stream a file as decoded UTF-8 text chunks. Refuses a binary file (a NUL byte
260
+ * within the first 8 KiB), an ill-formed UTF-8 file (at its byte offset), and
261
+ * an abort; strips one leading byte-order mark and records it. Breaking out of
262
+ * the loop destroys the underlying stream, so a reader that stops early never
263
+ * reads the rest of the file.
264
+ */
265
+ export async function* streamTextChunks(path: string, options: TextStreamOptions): AsyncGenerator<TextChunk, void> {
266
+ const { signal, stats } = options;
267
+ throwIfAborted(signal, path);
268
+ const stream = createReadStream(path, { highWaterMark: options.highWaterMark ?? DEFAULT_HIGH_WATER_MARK });
269
+ const onAbort = (): void => {
270
+ stream.destroy(new DataRefusalError(abortedRefusal(path)));
271
+ };
272
+ signal?.addEventListener("abort", onAbort, { once: true });
273
+ const decoder = new Utf8StreamDecoder();
274
+ let sniffRemaining = BINARY_SNIFF_BYTES;
275
+ let first = true;
276
+ try {
277
+ for await (const raw of stream) {
278
+ const chunk = raw as Buffer;
279
+ throwIfAborted(signal, path);
280
+ stats.bytesRead += chunk.length;
281
+ if (sniffRemaining > 0) {
282
+ const probe = chunk.subarray(0, Math.min(sniffRemaining, chunk.length));
283
+ const nul = probe.indexOf(0);
284
+ if (nul !== -1) {
285
+ throw new DataRefusalError(
286
+ refusal("binary", `NUL byte at offset ${stats.bytesRead - chunk.length + nul}; this is a binary file`, {
287
+ byteOffset: stats.bytesRead - chunk.length + nul,
288
+ }),
289
+ );
290
+ }
291
+ sniffRemaining -= probe.length;
292
+ }
293
+ let byteOffset = decoder.position;
294
+ let text = decoder.push(chunk);
295
+ if (first) {
296
+ first = false;
297
+ if (text.startsWith("")) {
298
+ stats.bom = true;
299
+ text = text.slice(1);
300
+ byteOffset += 3;
301
+ }
302
+ }
303
+ if (text.length > 0) yield { text, byteOffset };
304
+ }
305
+ decoder.end();
306
+ } catch (error) {
307
+ throw error instanceof DataRefusalError ? error : new DataRefusalError(refusalFromError(error, path, signal));
308
+ } finally {
309
+ signal?.removeEventListener("abort", onAbort);
310
+ stream.destroy();
311
+ }
312
+ }
313
+
314
+ export type CellClass = "empty" | "sentinel" | "integer" | "float" | "boolean" | "date" | "string";
315
+ export type ColumnType = "integer" | "float" | "boolean" | "date" | "string" | "empty" | "mixed";
316
+
317
+ /** Tokens counted as missing-value sentinels. Counted, never converted. */
318
+ export const SENTINEL_TOKENS: ReadonlySet<string> = new Set(["NA", "N/A", "NaN", "null", "NULL", "None", "-"]);
319
+
320
+ const INTEGER_PATTERN = /^[+-]?\d+$/u;
321
+ const FLOAT_PATTERN = /^[+-]?(?:\d+\.\d*|\.\d+|\d+)(?:[eE][+-]?\d+)?$/u;
322
+ const BOOLEAN_PATTERN = /^(?:true|false)$/iu;
323
+ const DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(?:[T ]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2})?)?$/u;
324
+
325
+ /** Classify one CSV cell by its source text. Whitespace is content: " " is a string, "" is empty. */
326
+ export function classifyCell(text: string): CellClass {
327
+ if (text.length === 0) return "empty";
328
+ if (SENTINEL_TOKENS.has(text)) return "sentinel";
329
+ if (INTEGER_PATTERN.test(text)) return "integer";
330
+ if (FLOAT_PATTERN.test(text)) return "float";
331
+ if (BOOLEAN_PATTERN.test(text)) return "boolean";
332
+ if (DATE_PATTERN.test(text)) return "date";
333
+ return "string";
334
+ }
335
+
336
+ export function emptyCellHistogram(): Record<CellClass, number> {
337
+ return { empty: 0, sentinel: 0, integer: 0, float: 0, boolean: 0, date: 0, string: 0 };
338
+ }
339
+
340
+ /**
341
+ * The column type a histogram of cell classes supports. Only typed cells vote:
342
+ * empties and sentinels are missing values, not evidence of a type. Integers
343
+ * and floats together are float; any other mixture is mixed.
344
+ */
345
+ export function inferColumnType(histogram: Record<CellClass, number>): ColumnType {
346
+ const typed = (["integer", "float", "boolean", "date", "string"] as const).filter((cls) => histogram[cls] > 0);
347
+ if (typed.length === 0) return "empty";
348
+ if (typed.length === 1) return typed[0] as ColumnType;
349
+ if (typed.every((cls) => cls === "integer" || cls === "float")) return "float";
350
+ return "mixed";
351
+ }
352
+
353
+ export type PrecisionKind =
354
+ | "unsafe-integer"
355
+ | "excess-digits"
356
+ | "inexact"
357
+ | "overflow"
358
+ | "underflow"
359
+ | "oversized-literal";
360
+
361
+ export interface PrecisionIssue {
362
+ kind: PrecisionKind;
363
+ literal: string;
364
+ /** JSON pointer of the value (JSON and JSONL). */
365
+ path?: string;
366
+ /** 1-based data row (CSV) or record line (JSONL). */
367
+ row?: number;
368
+ line?: number;
369
+ /** 0-based column index (CSV). */
370
+ column?: number;
371
+ }
372
+
373
+ const MAX_SIGNIFICANT_DIGITS = 17;
374
+ export const MAX_NUMBER_LITERAL_CHARS = 512;
375
+
376
+ /**
377
+ * Canonical decimal form of a number literal: sign, significant digits with
378
+ * leading and trailing zeros stripped, and a decimal exponent. Two literals
379
+ * denote the same real number exactly when their canonical forms match, which
380
+ * makes the form comparable across the source text and what JavaScript prints
381
+ * for the double it parsed to. Null when the text is not a plain decimal.
382
+ */
383
+ function canonicalDecimal(literal: string): string | null {
384
+ const match = /^([+-]?)(\d*)(?:\.(\d*))?(?:[eE]([+-]?\d+))?$/u.exec(literal);
385
+ if (match === null) return null;
386
+ const intDigits = match[2] ?? "";
387
+ const fracDigits = match[3] ?? "";
388
+ if (intDigits.length === 0 && fracDigits.length === 0) return null;
389
+ let digits = (intDigits + fracDigits).replace(/^0+/u, "");
390
+ if (digits.length === 0) return "0";
391
+ let exponent = Number(match[4] ?? "0") - fracDigits.length;
392
+ const trimmed = digits.replace(/0+$/u, "");
393
+ exponent += digits.length - trimmed.length;
394
+ digits = trimmed;
395
+ return `${match[1] === "-" ? "-" : ""}${digits}e${exponent}`;
396
+ }
397
+
398
+ /**
399
+ * Whether reading this number literal as an IEEE double would misstate what
400
+ * the text says. The double is judged by its canonical decimal form: when the
401
+ * shortest round-trip form JavaScript prints for it differs from the literal's
402
+ * own canonical form, the double does not denote the literal's value. The kind
403
+ * names why: an integer beyond 2^53 - 1, more than 17 significant digits, a
404
+ * value that overflows to infinity, one that underflows to zero, or a literal
405
+ * within those limits that still has no exact double (`inexact`). A literal the
406
+ * double represents exactly returns null.
407
+ */
408
+ export function numberLiteralPrecision(literal: string): PrecisionKind | null {
409
+ if (literal.length > MAX_NUMBER_LITERAL_CHARS) return "oversized-literal";
410
+ const canonical = canonicalDecimal(literal);
411
+ if (canonical === null) return null;
412
+ const value = Number(literal);
413
+ if (!Number.isFinite(value)) return "overflow";
414
+ if (value === 0) return canonical === "0" ? null : "underflow";
415
+ if (canonical === canonicalDecimal(String(value))) return null;
416
+ const exponentAt = canonical.indexOf("e");
417
+ const digits = canonical.slice(canonical.startsWith("-") ? 1 : 0, exponentAt);
418
+ const exponent = Number(canonical.slice(exponentAt + 1));
419
+ if (exponent >= 0 && Math.abs(value) > Number.MAX_SAFE_INTEGER) return "unsafe-integer";
420
+ if (digits.length > MAX_SIGNIFICANT_DIGITS) return "excess-digits";
421
+ return "inexact";
422
+ }
423
+
424
+ /**
425
+ * Row bound for a scan. `undefined` takes the default, `null` (or a
426
+ * non-finite number) means unbounded, and anything else is clamped to at
427
+ * least one row.
428
+ */
429
+ export function resolveMaxRows(value: number | null | undefined, fallback: number): number {
430
+ if (value === undefined) return fallback;
431
+ if (value === null || !Number.isFinite(value)) return Number.POSITIVE_INFINITY;
432
+ return Math.max(1, Math.floor(value));
433
+ }
434
+
435
+ export const SAMPLE_TEXT_CAP = 512;
436
+
437
+ /** Bound one sample cell for a report; the flag says whether anything was cut. */
438
+ export function capText(text: string, cap = SAMPLE_TEXT_CAP): { text: string; truncated: boolean } {
439
+ if (text.length <= cap) return { text, truncated: false };
440
+ return { text: `${Array.from(text).slice(0, cap).join("")}…`, truncated: true };
441
+ }
442
+
443
+ export function sampledNotice(rowsScanned: number, unit: string): string {
444
+ return `sampled: ${rowsScanned} ${unit} scanned of an unknown total; counts are lower bounds and rowCount is null`;
445
+ }
446
+
447
+ /** Deterministic histogram rendering: insertion order, plain object. */
448
+ export function histogramRecord(map: ReadonlyMap<string, number>): Record<string, number> {
449
+ const out: Record<string, number> = {};
450
+ for (const [key, count] of map) out[key] = count;
451
+ return out;
452
+ }
@@ -40,13 +40,6 @@ export interface EditDiffResult {
40
40
  firstChangedLine: number | undefined;
41
41
  }
42
42
 
43
- export function detectLineEnding(content: string): "\r\n" | "\n" {
44
- const crlfIdx = content.indexOf("\r\n");
45
- const lfIdx = content.indexOf("\n");
46
- if (lfIdx === -1 || crlfIdx === -1) return "\n";
47
- return crlfIdx < lfIdx ? "\r\n" : "\n";
48
- }
49
-
50
43
  export function normalizeToLF(text: string): string {
51
44
  return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
52
45
  }
package/src/tools/edit.ts CHANGED
@@ -1,19 +1,99 @@
1
- import { readFileSync, writeFileSync } from "node:fs";
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import { setImmediate as yieldImmediate } from "node:timers/promises";
2
3
  import { Type } from "typebox";
3
4
  import { ToolNames } from "../core/tool-names.js";
4
5
  import {
5
6
  applyEditsToNormalizedContent,
6
- detectLineEnding,
7
7
  type Edit,
8
8
  generateDiffString,
9
9
  normalizeToLF,
10
10
  restoreLineEndings,
11
11
  stripBom,
12
12
  } from "./edit-diff.js";
13
- import { withFileMutationQueue } from "./file-mutation-queue.js";
13
+ import { publishFileAtomically, withFileMutationQueue } from "./file-mutation-queue.js";
14
14
  import { resolveToCwd } from "./path-utils.js";
15
15
  import type { ToolResult, ToolSpec } from "./registry.js";
16
16
 
17
+ const DIFF_LIMIT = 1024 * 1024;
18
+ const VALIDATION_CHUNK = 64 * 1024;
19
+
20
+ async function invalidUtf8Offset(bytes: Buffer): Promise<number> {
21
+ const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
22
+ let failingStart = 0;
23
+ for (let start = 0; start < bytes.length; start += VALIDATION_CHUNK) {
24
+ try {
25
+ decoder.decode(bytes.subarray(start, start + VALIDATION_CHUNK), { stream: true });
26
+ } catch {
27
+ failingStart = start;
28
+ break;
29
+ }
30
+ failingStart = Math.min(start + VALIDATION_CHUNK, bytes.length);
31
+ await yieldImmediate();
32
+ }
33
+ // Include the previous code point when a sequence crosses the chunk boundary.
34
+ let start = Math.max(0, failingStart - 4);
35
+ while (start > 0 && ((bytes[start] ?? 0) & 0xc0) === 0x80) start -= 1;
36
+ const narrow = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
37
+ let sequenceStart = start;
38
+ const end = Math.min(bytes.length, failingStart + VALIDATION_CHUNK);
39
+ for (let i = start; i < end; i += 1) {
40
+ try {
41
+ if (narrow.decode(bytes.subarray(i, i + 1), { stream: true }).length > 0) sequenceStart = i + 1;
42
+ } catch {
43
+ return sequenceStart;
44
+ }
45
+ if ((i - start + 1) % 1024 === 0) await yieldImmediate();
46
+ }
47
+ return sequenceStart;
48
+ }
49
+
50
+ async function classifyEndings(bytes: Buffer): Promise<"\n" | "\r\n"> {
51
+ let crlf = false;
52
+ let lf = false;
53
+ let nextYield = VALIDATION_CHUNK;
54
+ for (let i = 0; i < bytes.length; i += 1) {
55
+ if (bytes[i] === 0) throw new Error(`NUL byte at byte offset ${i}; refusing binary input`);
56
+ if (bytes[i] === 13) {
57
+ if (bytes[i + 1] !== 10) throw new Error("Mixed or bare-CR line endings are unsupported; nothing was normalized");
58
+ crlf = true;
59
+ i += 1;
60
+ } else if (bytes[i] === 10) lf = true;
61
+ if (crlf && lf) throw new Error("Mixed or bare-CR line endings are unsupported; nothing was normalized");
62
+ if (i >= nextYield) {
63
+ nextYield = i + VALIDATION_CHUNK;
64
+ await yieldImmediate();
65
+ }
66
+ }
67
+ return crlf ? "\r\n" : "\n";
68
+ }
69
+
70
+ /** Large edits keep original endings and slice only the matched regions. */
71
+ function applyLargeExactEdits(content: string, edits: Edit[], ending: "\n" | "\r\n"): string {
72
+ const matches = edits
73
+ .map((edit, editIndex) => {
74
+ const oldText = restoreLineEndings(normalizeToLF(edit.oldText), ending);
75
+ if (!oldText) throw new Error(`edits[${editIndex}].oldText must not be empty`);
76
+ const index = content.indexOf(oldText);
77
+ if (index < 0)
78
+ throw new Error("Files above 1 MiB require exact matches; fuzzy matching is skipped to bound allocation");
79
+ if (content.indexOf(oldText, index + oldText.length) >= 0)
80
+ throw new Error("The text must be unique; provide more context");
81
+ return { index, length: oldText.length, replacement: restoreLineEndings(normalizeToLF(edit.newText), ending) };
82
+ })
83
+ .sort((a, b) => a.index - b.index);
84
+ const pieces: string[] = [];
85
+ let cursor = 0;
86
+ for (const entry of matches) {
87
+ if (entry.index < cursor) throw new Error("Edits overlap; target disjoint regions");
88
+ pieces.push(content.slice(cursor, entry.index), entry.replacement);
89
+ cursor = entry.index + entry.length;
90
+ }
91
+ pieces.push(content.slice(cursor));
92
+ const result = pieces.join("");
93
+ if (result === content) throw new Error("No changes made; replacements produced identical content");
94
+ return result;
95
+ }
96
+
17
97
  const editEntrySchema = Type.Object({
18
98
  oldText: Type.String({ description: "Exact unique text to replace; must not overlap other edits." }),
19
99
  newText: Type.String({ description: "Replacement text." }),
@@ -68,7 +148,7 @@ function prepareEditArguments(args: Record<string, unknown>): Record<string, unk
68
148
  export const editTool: ToolSpec = {
69
149
  name: ToolNames.Edit,
70
150
  description:
71
- "Edit one file with exact text replacements. Each oldText must match a unique region of the original file.",
151
+ "Edit one file with exact text replacements. Each oldText must match a unique region of the original file. Matching tries exact text first, then quote/dash/NFKC and trailing-space normalization, then indentation relaxation. Files above 1 MiB require exact matches and skip diffs to bound allocation. Refuses NUL bytes, invalid UTF-8, and mixed or bare-CR line endings. LF replacement text adopts the file’s LF or CRLF endings; the UTF-8 BOM is preserved. Publishes atomically through symlinks with mode bits preserved. External writers are not locked; the last rename wins. Returned file identities describe publication, not a precondition on an earlier model read.",
72
152
  parameters: Type.Object({
73
153
  path: Type.String({ description: "File path (relative or absolute)." }),
74
154
  edits: Type.Array(editEntrySchema, { description: "One or more targeted replacements." }),
@@ -90,17 +170,29 @@ export const editTool: ToolSpec = {
90
170
 
91
171
  try {
92
172
  return await withFileMutationQueue(filePath, async () => {
93
- const rawContent = readFileSync(filePath, "utf8");
173
+ const info = await stat(filePath);
174
+ if (!info.isFile()) throw new Error("Refusing directory or non-file target");
175
+ const bytes = await readFile(filePath);
176
+ const originalEnding = await classifyEndings(bytes);
177
+ let rawContent: string;
178
+ try {
179
+ rawContent = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
180
+ } catch {
181
+ throw new Error(`Invalid UTF-8 at byte offset ${await invalidUtf8Offset(bytes)}`);
182
+ }
94
183
  const { bom, text: content } = stripBom(rawContent);
95
- const originalEnding = detectLineEnding(content);
96
- const normalizedContent = normalizeToLF(content);
97
- const applied = {
98
- ...applyEditsToNormalizedContent(normalizedContent, edits, pathArg),
99
- replacements: edits.length,
100
- };
101
- const finalContent = bom + restoreLineEndings(applied.newContent, originalEnding);
102
- writeFileSync(filePath, finalContent, "utf8");
103
- const diff = generateDiffString(applied.baseContent, applied.newContent);
184
+ let finalContent: string;
185
+ let diff: ReturnType<typeof generateDiffString> | undefined;
186
+ if (bytes.length > DIFF_LIMIT) {
187
+ finalContent = bom + applyLargeExactEdits(content, edits, originalEnding);
188
+ } else {
189
+ const applied = applyEditsToNormalizedContent(normalizeToLF(content), edits, pathArg);
190
+ finalContent = bom + restoreLineEndings(applied.newContent, originalEnding);
191
+ if (Buffer.byteLength(finalContent, "utf8") <= DIFF_LIMIT) {
192
+ diff = generateDiffString(applied.baseContent, applied.newContent);
193
+ }
194
+ }
195
+ const file = await publishFileAtomically(filePath, finalContent);
104
196
  // The validation nudge is point-of-failure conditioning: measured on
105
197
  // a live 35B coder worker, the model edited correctly and then spent
106
198
  // its remaining calls "validating" with navigation tools (code_nav
@@ -109,8 +201,13 @@ export const editTool: ToolSpec = {
109
201
  // every agent sees at exactly the moment it matters.
110
202
  return {
111
203
  kind: "ok",
112
- output: `edited ${pathArg}: ${applied.replacements} replacement(s). Validate now: rerun the failing test or verify; navigation tools do not validate edits.`,
113
- details: { diff: diff.diff, firstChangedLine: diff.firstChangedLine, paths: [filePath] },
204
+ output: `edited ${pathArg}: ${edits.length} replacement(s). Validate now: rerun the failing test or verify; navigation tools do not validate edits.${!diff ? "\nnote: diff skipped because the previous or new file exceeds 1 MiB" : ""}${file.durabilityWarning ? `\n${file.durabilityWarning}` : ""}`,
205
+ details: {
206
+ file: { before: file.before, after: file.after },
207
+ diff: diff?.diff,
208
+ firstChangedLine: diff?.firstChangedLine,
209
+ paths: [filePath],
210
+ },
114
211
  };
115
212
  });
116
213
  } catch (err) {
@@ -119,10 +216,10 @@ export const editTool: ToolSpec = {
119
216
  if (code === "ENOENT") {
120
217
  return {
121
218
  kind: "error",
122
- message: `edit: ${msg}. File not found at ${pathArg}. The path may be wrong. Try: code_nav, find, glob, or ls to locate it.`,
219
+ message: `edit: Nothing was published. ${msg}. File not found at ${pathArg}. The path may be wrong. Try: code_nav, find, glob, or ls to locate it.`,
123
220
  };
124
221
  }
125
- return { kind: "error", message: `edit: ${msg}` };
222
+ return { kind: "error", message: `edit: Nothing was published. ${msg}` };
126
223
  }
127
224
  },
128
225
  };