@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.
- package/CHANGELOG.md +92 -2
- package/CONTRIBUTING.md +25 -15
- package/README.md +340 -27
- package/dist/{acp-WNAYYF4F.js → acp-H3CU2HBQ.js} +25 -24
- package/dist/{agents-3OKXHLOI.js → agents-IXQQZ7BD.js} +77 -77
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-VKNNMGPU.js → auth-R7KYF7N3.js} +38 -38
- package/dist/builtins-CRFDQUVP.js +22 -0
- package/dist/{chunk-TQAHXW6Y.js → chunk-22PQ4TX4.js} +4 -4
- package/dist/{chunk-NEDJ26B5.js → chunk-2GPGAE5W.js} +6 -51
- package/dist/{chunk-IKCO5N3L.js → chunk-2QPI3TR3.js} +3 -3
- package/dist/{chunk-HRQMFLJP.js → chunk-32KJPXAM.js} +6 -6
- package/dist/{chunk-65DEGPJ6.js → chunk-3A3CUMKA.js} +6 -4
- package/dist/{chunk-JCI2ROMZ.js → chunk-3T4DXWP6.js} +7 -7
- package/dist/{chunk-DR52UMZW.js → chunk-3UW3KU4A.js} +2 -2
- package/dist/{chunk-6Q3CYFD3.js → chunk-4SVIVOMC.js} +184 -33
- package/dist/{chunk-W54I7H25.js → chunk-5A6XR3RJ.js} +44 -19
- package/dist/{chunk-YPC6ZR5L.js → chunk-5CMARGPF.js} +119 -5
- package/dist/{chunk-KXDSS5WJ.js → chunk-5CY4Q6QI.js} +4 -4
- package/dist/{chunk-I2DWJ4GM.js → chunk-5DDOTTG4.js} +54 -42
- package/dist/{chunk-D4CJV46V.js → chunk-5GZICIYO.js} +3 -3
- package/dist/{chunk-4IUZQIJ3.js → chunk-5PHVPU4G.js} +2 -2
- package/dist/{chunk-3ODX73FK.js → chunk-5VTJP36Q.js} +4 -4
- package/dist/{chunk-54X7T7DK.js → chunk-5ZMXGW7P.js} +79 -7
- package/dist/chunk-5ZSZEYJK.js +119 -0
- package/dist/{chunk-IXIY2H4R.js → chunk-633EXGZA.js} +5 -5
- package/dist/{chunk-CUSRQKPU.js → chunk-6CDNRHWH.js} +299 -89
- package/dist/{chunk-EBY63B7G.js → chunk-6EXUUOSN.js} +2 -2
- package/dist/{chunk-SVNXH4L2.js → chunk-6ICZKDUC.js} +2 -2
- package/dist/{chunk-JEIYHLOR.js → chunk-6SYEGZI3.js} +12 -12
- package/dist/{chunk-DQOVN6KV.js → chunk-6YA46L5A.js} +4 -4
- package/dist/{chunk-NZMNUPZZ.js → chunk-77CZRFTE.js} +3 -3
- package/dist/{chunk-6PAZTBPA.js → chunk-7HBHHVCK.js} +15 -6
- package/dist/{chunk-25QBEXRS.js → chunk-7TKWWPD7.js} +5 -4
- package/dist/{chunk-2VTFPG5O.js → chunk-7WLRF2U5.js} +2 -2
- package/dist/chunk-7WUZEB2M.js +165 -0
- package/dist/{chunk-3UUXNFEX.js → chunk-7YJWEF2L.js} +61 -34
- package/dist/{chunk-3EBYEESD.js → chunk-A46ILRS2.js} +5 -5
- package/dist/{chunk-UOIZ7DA4.js → chunk-AP7HDJOP.js} +2 -2
- package/dist/{chunk-APJ265NV.js → chunk-B5GGDIHT.js} +146 -146
- package/dist/{chunk-PMZVFWSR.js → chunk-B5ZTR6KZ.js} +2 -2
- package/dist/{chunk-I5FWO7L5.js → chunk-B6UM3OZC.js} +2 -2
- package/dist/{chunk-2CU2H6KE.js → chunk-BBV5TKE6.js} +5 -5
- package/dist/{chunk-4O6MANBS.js → chunk-BS4GAMUB.js} +14 -10
- package/dist/{chunk-S66XZJOF.js → chunk-C27U2TYG.js} +2 -2
- package/dist/{chunk-QZWQA4DE.js → chunk-CBSKDFWL.js} +3 -3
- package/dist/{chunk-2LEAKD4C.js → chunk-CKK25WN3.js} +3 -3
- package/dist/{chunk-BYP5D4HI.js → chunk-CTTI7G3T.js} +2 -2
- package/dist/{chunk-XAKHZX5N.js → chunk-CVDAFGPW.js} +4 -4
- package/dist/{chunk-RKKLTLYB.js → chunk-CXQ37WJH.js} +3 -3
- package/dist/{chunk-GTUD2WMY.js → chunk-DBREN25X.js} +44 -9
- package/dist/{chunk-YNFKXPEC.js → chunk-DIMRLNIC.js} +35 -66
- package/dist/{chunk-NDDGJUXD.js → chunk-DNCE23JJ.js} +2 -2
- package/dist/{chunk-HVDIIIQW.js → chunk-DNHVRBH4.js} +3 -3
- package/dist/{chunk-XULDXHTN.js → chunk-DRD2A54W.js} +102 -50
- package/dist/{chunk-D7E7WCDF.js → chunk-DVNAPPXU.js} +2 -2
- package/dist/{chunk-YXLYO42X.js → chunk-DXVMLM3Z.js} +3 -2
- package/dist/{chunk-5MEZN6CB.js → chunk-DZK63TZJ.js} +6 -6
- package/dist/{chunk-IGLP3ODT.js → chunk-E3BQTQUP.js} +15 -15
- package/dist/{chunk-IWHMRKLL.js → chunk-E3LEPLQ2.js} +2 -2
- package/dist/{chunk-3R73A4XB.js → chunk-ECBHH7LU.js} +3 -3
- package/dist/chunk-ECOMVOHP.js +139 -0
- package/dist/chunk-EFSEIZE6.js +56 -0
- package/dist/{chunk-FEAXX7B6.js → chunk-EHCPSZJF.js} +4 -4
- package/dist/{chunk-4NSRCOYP.js → chunk-EHOSNVVM.js} +3 -2
- package/dist/{chunk-7UGL4MB5.js → chunk-EQEJJ53P.js} +10 -10
- package/dist/{chunk-GWZNEVM2.js → chunk-EWD5P3GK.js} +9 -9
- package/dist/{chunk-6UINWWS6.js → chunk-F34AR6O3.js} +14 -14
- package/dist/{chunk-GHS5EBTQ.js → chunk-FKIOX6DS.js} +29 -20
- package/dist/{chunk-HAXOFFRH.js → chunk-FQOOGXBH.js} +7 -7
- package/dist/{chunk-Y55JBDO5.js → chunk-FSTIBAGM.js} +38 -23
- package/dist/{chunk-ZTJUVLTU.js → chunk-FXFVDPWY.js} +2 -2
- package/dist/{chunk-XPLRXC72.js → chunk-GD55RTIW.js} +3 -3
- package/dist/{chunk-5B2AEOW5.js → chunk-GH5ZR6JP.js} +472 -472
- package/dist/{chunk-TOIVGRUX.js → chunk-GJ24ODAX.js} +5 -5
- package/dist/{chunk-QUFRYSWI.js → chunk-GNQRWTMY.js} +129 -48
- package/dist/{chunk-5ICU3EUH.js → chunk-GVYWZNRK.js} +5 -5
- package/dist/{chunk-GX5WYQO4.js → chunk-GXCCHKN6.js} +6 -6
- package/dist/{chunk-K6T2ZAMZ.js → chunk-HGSLRG33.js} +6 -6
- package/dist/{chunk-26QSH3EJ.js → chunk-HHVJNVUJ.js} +5 -5
- package/dist/{chunk-F4EKGO4N.js → chunk-HL26ADLH.js} +4 -2
- package/dist/{chunk-JT2RFCC5.js → chunk-HR3HPQ76.js} +5 -5
- package/dist/{chunk-ID64D7PE.js → chunk-HXHFDHB6.js} +24 -24
- package/dist/{chunk-ELWDPP3Y.js → chunk-I7VLWRK2.js} +8 -8
- package/dist/{chunk-6OSVSQL5.js → chunk-ICO4TQ2F.js} +7 -5
- package/dist/{chunk-SZAA6XDG.js → chunk-IFDRAD6F.js} +2 -2
- package/dist/{chunk-72YIHOZQ.js → chunk-ILJ7DWGE.js} +9 -9
- package/dist/{chunk-2JH2WHGE.js → chunk-J2FYEQ5L.js} +4 -4
- package/dist/{chunk-BMS5RKQY.js → chunk-JABWPKFY.js} +3 -3
- package/dist/{chunk-QDC3K2U3.js → chunk-K2BLQC5E.js} +3 -3
- package/dist/{chunk-AUPNRN7C.js → chunk-K2HL3GBL.js} +4 -4
- package/dist/{chunk-2ASED4PZ.js → chunk-K6RDB7IA.js} +26 -26
- package/dist/{chunk-FFUPXJC4.js → chunk-KDWLXVMN.js} +23 -24
- package/dist/{chunk-OZNBF4L3.js → chunk-KECNXMDE.js} +2 -2
- package/dist/{chunk-6QOTUPRG.js → chunk-KF6GFW6O.js} +66 -18
- package/dist/{chunk-BTK3SSSK.js → chunk-KMF54VH3.js} +2 -2
- package/dist/chunk-KPRLAMP4.js +32 -0
- package/dist/{chunk-ECH6PKUQ.js → chunk-KQ6IDQIB.js} +2 -2
- package/dist/{chunk-3UNOLWNZ.js → chunk-KTFSFCVN.js} +20 -9
- package/dist/{chunk-57XXR6DR.js → chunk-KYKNBD4Y.js} +24 -23
- package/dist/{chunk-IRXAATOX.js → chunk-L4N3DWNW.js} +3 -3
- package/dist/{chunk-LCGCVYZ4.js → chunk-LQTKDAUO.js} +2 -2
- package/dist/{chunk-U6TMQNSI.js → chunk-LTR5QCLS.js} +4 -4
- package/dist/chunk-LUL5Z66S.js +221 -0
- package/dist/{chunk-ELZVTCGV.js → chunk-LVFANMOH.js} +151 -327
- package/dist/{chunk-H7IXIC72.js → chunk-LY4N4TTL.js} +17 -3
- package/dist/{chunk-VKPAQYEB.js → chunk-LZBMXNLP.js} +5 -5
- package/dist/{chunk-UL3WSD3F.js → chunk-M4KFUXS7.js} +2 -2
- package/dist/{chunk-NXYCB2VD.js → chunk-M6TAYK66.js} +6 -6
- package/dist/{chunk-NEKRRTYW.js → chunk-MC3JSVR6.js} +2 -2
- package/dist/{chunk-CFGTUFWB.js → chunk-MCJKEGHO.js} +2 -2
- package/dist/{chunk-DXKJURES.js → chunk-MDU3C27C.js} +10 -7
- package/dist/{chunk-6XLNIQDB.js → chunk-MYI32N4R.js} +2 -2
- package/dist/{chunk-3GY4F45V.js → chunk-NC4KV7EL.js} +6 -6
- package/dist/{chunk-LLXSDWXS.js → chunk-NF3BK5WR.js} +5 -5
- package/dist/chunk-NTK3WTHM.js +141 -0
- package/dist/{chunk-GYV6VZOC.js → chunk-NTTS3O53.js} +2 -2
- package/dist/{chunk-RZDWV63N.js → chunk-NY6IWDVU.js} +6 -6
- package/dist/{chunk-XXYSBZIQ.js → chunk-O2RQ7LCK.js} +4 -4
- package/dist/{chunk-4BJ5BYCE.js → chunk-O3VV6IVK.js} +2 -2
- package/dist/{chunk-W6GROXXM.js → chunk-O5F25NIE.js} +2 -2
- package/dist/{chunk-NXIMQY5W.js → chunk-ODUTYZIU.js} +5 -5
- package/dist/{chunk-LTIKRKFL.js → chunk-ONRTXOZY.js} +4 -4
- package/dist/{chunk-KFV5L5SK.js → chunk-OQM5IVJY.js} +118 -232
- package/dist/{chunk-XRZT5WY5.js → chunk-P5SC4DLJ.js} +4 -4
- package/dist/{chunk-R6Q67RJH.js → chunk-PECBKCDK.js} +34 -6
- package/dist/{chunk-33YXPOE3.js → chunk-PPEZJWUG.js} +2 -2
- package/dist/{chunk-RXTN6AKH.js → chunk-PWWSIB2A.js} +5 -5
- package/dist/{chunk-2STGEDFV.js → chunk-QEQISF75.js} +2 -2
- package/dist/{chunk-3DPEIQKN.js → chunk-QH3ZTUOA.js} +2 -2
- package/dist/{chunk-YAKGTXEV.js → chunk-QRFXEO6Y.js} +2 -2
- package/dist/{chunk-35MSIRKH.js → chunk-QUIJZSDW.js} +2 -2
- package/dist/{chunk-HHV2GANA.js → chunk-R2P2U3ZS.js} +2 -2
- package/dist/{chunk-2DSOYNFC.js → chunk-R6MAYTMS.js} +7 -7
- package/dist/{chunk-JQLNNIKT.js → chunk-R6MICQYU.js} +6 -6
- package/dist/{chunk-NAI6ZFCY.js → chunk-RLTT5GVY.js} +122 -11
- package/dist/{chunk-DT3LWJOB.js → chunk-RXIOCVBZ.js} +24 -6
- package/dist/{chunk-N56KALIC.js → chunk-S32UQ5GL.js} +61 -34
- package/dist/{chunk-UEPWCCTY.js → chunk-SBZX6ARC.js} +12 -12
- package/dist/chunk-SD7SHNDW.js +15 -0
- package/dist/{chunk-NRO2BJRH.js → chunk-SDWNDICN.js} +10235 -4015
- package/dist/{chunk-UXCU4E3T.js → chunk-SE4ZKILO.js} +6 -6
- package/dist/chunk-SL2RDHKO.js +19 -0
- package/dist/{chunk-NUGM5KR6.js → chunk-SRCEQKQS.js} +2 -2
- package/dist/{chunk-OMQNJVKW.js → chunk-SRZOW5L2.js} +43 -13
- package/dist/{chunk-3M6DQK6S.js → chunk-T334FW2H.js} +7 -7
- package/dist/{chunk-V76WTFTW.js → chunk-T52TPHYC.js} +6 -6
- package/dist/{chunk-I7XBWTYH.js → chunk-T53XI6I7.js} +5 -5
- package/dist/{chunk-2ZSONWVL.js → chunk-T7FDXNRU.js} +13 -13
- package/dist/{chunk-JSD46VO2.js → chunk-TEG3RYVZ.js} +43 -36
- package/dist/{chunk-3I7MS7N2.js → chunk-TK2BMCBZ.js} +2 -2
- package/dist/{chunk-5OIVVPHF.js → chunk-TN5FW4XY.js} +13 -6
- package/dist/{chunk-75W7L2E2.js → chunk-TZ7MFRG4.js} +1041 -162
- package/dist/{chunk-36CT5VVL.js → chunk-U2JOLB7O.js} +126 -77
- package/dist/{chunk-LL4KHSZI.js → chunk-U2MSJ57E.js} +2 -2
- package/dist/{chunk-FTMGRKEF.js → chunk-U44YYLVV.js} +4 -4
- package/dist/{chunk-YECAMM3D.js → chunk-U7H5WRG5.js} +5 -5
- package/dist/{chunk-RQCKCSRL.js → chunk-U7VQ4NI4.js} +22 -22
- package/dist/{chunk-5TUB6SLS.js → chunk-UFYNOQK4.js} +7 -7
- package/dist/{chunk-R346GLFC.js → chunk-UHW5V7HC.js} +2 -2
- package/dist/{chunk-USR47QNF.js → chunk-UL36QJX6.js} +14 -14
- package/dist/{chunk-VIA6RFQZ.js → chunk-UQIVHSE4.js} +4 -4
- package/dist/{chunk-RAY4OVGZ.js → chunk-URBGEOH3.js} +5 -5
- package/dist/chunk-USZA7GWL.js +341 -0
- package/dist/{chunk-YD5GIKET.js → chunk-UTUNT5QL.js} +48 -579
- package/dist/{chunk-ZA4VCIGV.js → chunk-UUQ5G6EZ.js} +60 -41
- package/dist/{chunk-23L32XTI.js → chunk-UXAC2FX4.js} +68 -39
- package/dist/{chunk-VG7TBQIY.js → chunk-V552WL53.js} +68 -4
- package/dist/{chunk-BWH6N36D.js → chunk-VHKTOLEW.js} +272 -42
- package/dist/{chunk-EXLD33WO.js → chunk-VLPTKCKT.js} +24 -9
- package/dist/{chunk-336NSSKI.js → chunk-VNBICSS2.js} +2 -2
- package/dist/{chunk-VAVR4IJY.js → chunk-VQD7NH7Z.js} +3 -3
- package/dist/{chunk-LBMZMYH2.js → chunk-W2RJEH6Q.js} +3 -3
- package/dist/{chunk-7CR24IG7.js → chunk-WDV62RKY.js} +2 -2
- package/dist/{chunk-S6PYF2XF.js → chunk-WFKDPU7U.js} +4 -4
- package/dist/{chunk-BJVFZO5U.js → chunk-WJIMKGD6.js} +7 -7
- package/dist/{chunk-5636DCO5.js → chunk-WLMSOT73.js} +59 -12
- package/dist/{chunk-MXHC5QYU.js → chunk-WTQGRBHV.js} +5 -144
- package/dist/chunk-WXA2CFJO.js +23 -0
- package/dist/{chunk-QSNYB6ZV.js → chunk-XCUDZQLX.js} +3 -3
- package/dist/{chunk-4M6Z5QVF.js → chunk-XXBQKW32.js} +11 -11
- package/dist/{chunk-OEJSLEPW.js → chunk-YEJIG7LN.js} +332 -332
- package/dist/chunk-YGDMBK7O.js +567 -0
- package/dist/{chunk-4WR7VSYB.js → chunk-YYB3MC65.js} +23 -9
- package/dist/{chunk-2IR2NMPA.js → chunk-ZIDFQJRB.js} +2 -2
- package/dist/{chunk-Q4WO54TA.js → chunk-ZMZQEBKI.js} +14 -14
- package/dist/{chunk-6EJMN2Y3.js → chunk-ZTNFYMIO.js} +2 -2
- package/dist/{chunk-WEPFGWHJ.js → chunk-ZZFWWYLX.js} +2 -2
- package/dist/cli/index.js +44 -44
- package/dist/clio-5I2IBFYL.js +26 -0
- package/dist/{code-nav-IJR2DBPR.js → code-nav-YXIAEZVS.js} +48 -32
- package/dist/codewiki/build-worker.js +76 -29
- package/dist/{compile-cache-OQAVB7Y5.js → compile-cache-WJEPUZEJ.js} +4 -4
- package/dist/{components-2TGAI2RC.js → components-TNIKXCBH.js} +13 -13
- package/dist/{config-IUA6OYNS.js → config-Y2JDJ3JJ.js} +210 -124
- package/dist/configure-SML6UBZ5.js +55 -0
- package/dist/{context-4MPR7WKB.js → context-P5YSEO55.js} +125 -121
- package/dist/{context-2DKHWH2T.js → context-QQ53HSGJ.js} +91 -62
- package/dist/{context-BOYF5EJM.js → context-S2EEC3EJ.js} +62 -31
- package/dist/context-clear-TMEQCOTH.js +183 -0
- package/dist/{context-index-HNG3MOME.js → context-index-HP2JFUWA.js} +13 -11
- package/dist/{context-map-COB37XXN.js → context-map-INTXD54D.js} +71 -21
- package/dist/{context-working-set-3I3FYX6Y.js → context-working-set-CNLSQN5K.js} +31 -31
- package/dist/detail-5572VLBO.js +114 -0
- package/dist/{dispatch-runner-RJ5I2F2O.js → dispatch-runner-FRHD6P2O.js} +191 -116
- package/dist/{docs-SPOV3BAN.js → docs-BL7ROUFN.js} +4 -4
- package/dist/{doctor-DKICC2SN.js → doctor-N3LCM2LG.js} +58 -58
- package/dist/{eval-OQOQUDHK.js → eval-BUU3ZOUZ.js} +473 -168
- package/dist/{eval-inventory-Y6QRFOH5.js → eval-inventory-QOYZERXJ.js} +7 -7
- package/dist/evidence-DTGEN456.js +224 -0
- package/dist/{evidence-4DQ25GUQ.js → evidence-SQ5DNFEN.js} +110 -94
- package/dist/{evolve-GSS52E5J.js → evolve-IJNUFZDS.js} +107 -91
- package/dist/{extensions-G7MFLYHT.js → extensions-YVRHX6ZI.js} +16 -16
- package/dist/{fleet-Q37YHHAQ.js → fleet-ZNNVSYFO.js} +147 -147
- package/dist/{fleet-commands-G7E4N7SM.js → fleet-commands-5YE7NPJL.js} +27 -26
- package/dist/{fleet-decisions-O7M6QBA2.js → fleet-decisions-3SBSCTCW.js} +16 -15
- package/dist/{fleet-graph-TOUBW6OW.js → fleet-graph-6HHPWF5T.js} +39 -38
- package/dist/{fleet-inspect-SW33JJNI.js → fleet-inspect-JEYMGCGC.js} +107 -91
- package/dist/{fleet-new-RDVJLHHH.js → fleet-new-RCKGSRDV.js} +3 -3
- package/dist/{fleet-preflight-CV2655TW.js → fleet-preflight-QRSHIIDE.js} +10 -9
- package/dist/{fleet-validate-KESZX2YH.js → fleet-validate-4PM4GDDL.js} +46 -42
- package/dist/{fleet-verify-UQPMTVE3.js → fleet-verify-NJDTHTO3.js} +105 -89
- package/dist/fleet-view-UP2BWQQY.js +117 -0
- package/dist/{init-PXEXQSBF.js → init-S3GZQ5ZF.js} +123 -123
- package/dist/{install-NKNG7KD4.js → install-3RZDDP23.js} +5 -5
- package/dist/{interop-ZG5T62U3.js → interop-YOTGXFJM.js} +25 -25
- package/dist/inventory-K2OZ36YJ.js +117 -0
- package/dist/{library-B2W4N74O.js → library-GJI6W6OK.js} +45 -44
- package/dist/{memory-YCANYS5A.js → memory-OQOXQGYD.js} +107 -93
- package/dist/{models-GERTU3YI.js → models-3IK2Y5WE.js} +63 -62
- package/dist/{monitor-CPNIUULB.js → monitor-FTJLTKCQ.js} +136 -107
- package/dist/{orchestrator-J4BSH4WQ.js → orchestrator-N47O7SFD.js} +1159 -697
- package/dist/{panes-BOHAEGYC.js → panes-7BTYH3XQ.js} +8 -8
- package/dist/{panes-NXSLDQZ2.js → panes-WPOMEMRH.js} +22 -22
- package/dist/{paths-VSUWNC22.js → paths-J3KN7UAO.js} +12 -12
- package/dist/preload-65U34NG6.js +115 -0
- package/dist/{registry-LG64LTF4.js → registry-DESGAXWK.js} +3 -3
- package/dist/{reset-TNWTB5LU.js → reset-MUVQDLNL.js} +20 -20
- package/dist/{resources-4PXNMD5G.js → resources-LM76COAO.js} +41 -40
- package/dist/{run-D6XJ34CN.js → run-3VFZQ33N.js} +162 -156
- package/dist/{share-2NWMJJEE.js → share-4JUB4BL7.js} +43 -42
- package/dist/{skills-KR7WON5G.js → skills-S36AAJHU.js} +47 -46
- package/dist/{skills-eval-O2ZNOLDS.js → skills-eval-G6T57L7M.js} +127 -107
- package/dist/{skills-inventory-ZZOUBK7O.js → skills-inventory-WLM46PJH.js} +41 -40
- package/dist/slash-commands-GBARG3Y7.js +91 -0
- package/dist/{steer-XA25PSCS.js → steer-S7D7IKPU.js} +7 -7
- package/dist/{support-7EMVWYG2.js → support-5VAEC32W.js} +14 -14
- package/dist/{targets-OMH2XCSN.js → targets-N5REUETU.js} +145 -94
- package/dist/tasks-6BVY5YZF.js +36 -0
- package/dist/{terminal-lease-C2J3JYRE.js → terminal-lease-57UEOJKS.js} +12 -11
- package/dist/tools-6OCQ6SVB.js +28 -0
- package/dist/{trace-FXMXUZUF.js → trace-JHLXWUMN.js} +18 -17
- package/dist/{tree-sitter-HGKH6LG4.js → tree-sitter-AQUUOSYM.js} +6 -6
- package/dist/{tui-primitives-K5PASC3O.js → tui-primitives-RCY2HN7G.js} +3 -3
- package/dist/{uninstall-HALS6BLF.js → uninstall-FXYMFFRT.js} +17 -17
- package/dist/{upgrade-MS72RJEP.js → upgrade-4HD5HAIV.js} +40 -39
- package/dist/{usage-NHG6MCJM.js → usage-4GWM2WWP.js} +136 -105
- package/dist/{verifiers-7AUNVXDY.js → verifiers-GSKWKWVG.js} +28 -27
- package/dist/verify-3AS3ULCY.js +30 -0
- package/dist/{version-KGEG7EPO.js → version-RFPKO6T7.js} +4 -4
- package/dist/{web-fetch-V4FKSDAV.js → web-fetch-MQN4FH3X.js} +169 -18
- package/dist/wiki-generate-7BV7XWIY.js +614 -0
- package/dist/{with-panes-BDQEWBRT.js → with-panes-OFTNAR4Y.js} +34 -20
- package/dist/worker/entry.js +99 -88
- package/dist/{workspace-ZJ6BFM3Q.js → workspace-DZ7JADBG.js} +6 -6
- package/docs/README.md +7 -6
- package/docs/architecture/acp.md +10 -0
- package/docs/architecture/architecture.md +5 -5
- package/docs/architecture/context-engine.md +44 -59
- package/docs/architecture/context-working-set.md +7 -9
- package/docs/architecture/dispatch-architecture-rationale.md +1 -1
- package/docs/architecture/evidence-and-memory.md +10 -0
- package/docs/architecture/pi-boundary.md +37 -7
- package/docs/architecture/prompt-envelope-and-tools.md +7 -7
- package/docs/architecture/session-lifecycle.md +4 -4
- package/docs/architecture/worker-dispatch-mechanics.md +4 -0
- package/docs/guide/commands-and-modes.md +49 -36
- package/docs/guide/configuration-and-targets.md +7 -2
- package/docs/guide/configuration-reference.md +13 -3
- package/docs/guide/environment-variables.md +6 -2
- package/docs/guide/fleet-dispatch.md +12 -0
- package/docs/guide/installation-and-lifecycle.md +35 -9
- package/docs/guide/proactive-memory.md +1 -1
- package/docs/guide/skills-marketplace.md +11 -3
- package/docs/guide/tool-usage.md +9 -2
- package/docs/process/development-pipeline.md +10 -10
- package/docs/process/documentation-guide.md +2 -2
- package/docs/process/eval-runner.md +15 -0
- package/docs/process/evals-internal.md +1 -1
- package/docs/process/release-cut-checklist.md +6 -6
- package/evals/README.md +4 -0
- package/evals/behavioral-corpus-grader.mjs +147 -14
- package/evals/behavioral-model-negative-control.yaml +1 -0
- package/evals/behavioral-model.yaml +266 -1
- package/evals/fixtures/docs-retrieval.json +102 -0
- package/evals/fixtures/scalar-decision.json +17 -0
- package/evals/fixtures/scout-citation-pipeline.json +55 -0
- package/evals/fixtures/source-explanation.json +74 -0
- package/evals/fixtures/tool-arguments.json +18 -0
- package/evals/fixtures/tool-surface/read.txt +4 -0
- package/evals/fixtures/tool-surface/subdir/keep.txt +1 -0
- package/evals/no-edit-memory-grader.mjs +149 -0
- package/evals/scalar-decision-grader.py +41 -0
- package/evals/scalar-decision-machinery.ts +145 -0
- package/evals/source-explanation-grader.mjs +118 -0
- package/evals/tool-surface-grader.mjs +53 -0
- package/evals/tool-surface-model.yaml +274 -0
- package/package.json +14 -14
- package/skills/README.md +6 -6
- package/skills/registry.yaml +1 -1
- package/skills/skill-marketplace.json +1 -1
- package/src/cli/bootstrap-generate.ts +6 -0
- package/src/cli/config-inspect.ts +24 -7
- package/src/cli/config-trust.ts +62 -0
- package/src/cli/config.ts +8 -0
- package/src/cli/context-map.ts +75 -14
- package/src/cli/context.ts +46 -17
- package/src/cli/eval.ts +17 -3
- package/src/cli/modes/print.ts +32 -4
- package/src/cli/run.ts +16 -14
- package/src/cli/skills-eval.ts +10 -8
- package/src/cli/steer-channel.ts +31 -18
- package/src/cli/targets.ts +83 -31
- package/src/cli/tasks.ts +10 -1
- package/src/cli/upgrade.ts +9 -6
- package/src/cli/usage.ts +24 -0
- package/src/cli/wiki-generate.ts +239 -96
- package/src/core/bash-exec.ts +43 -15
- package/src/core/bus-events.ts +15 -0
- package/src/core/config.ts +33 -14
- package/src/core/defaults.ts +5 -4
- package/src/core/file-references.ts +11 -1
- package/src/core/incomplete-installation.ts +3 -1
- package/src/core/settings-layers.ts +21 -5
- package/src/core/termination.ts +26 -9
- package/src/core/untrusted-content.ts +16 -0
- package/src/core/workspace-trust.ts +179 -0
- package/src/domains/agents/builtins/coder.md +4 -2
- package/src/domains/agents/builtins/context-bootstrap.md +3 -1
- package/src/domains/agents/builtins/documenter.md +7 -4
- package/src/domains/agents/builtins/researcher.md +1 -0
- package/src/domains/agents/builtins/scout.md +7 -1
- package/src/domains/agents/result-contract.ts +199 -26
- package/src/domains/context/bootstrap-prompt.ts +11 -9
- package/src/domains/context/bootstrap.ts +74 -39
- package/src/domains/context/clio-md.ts +88 -26
- package/src/domains/context/codewiki/build-operation.ts +121 -0
- package/src/domains/context/codewiki/build-worker-protocol.ts +37 -3
- package/src/domains/context/codewiki/build-worker.ts +3 -35
- package/src/domains/context/codewiki/coordinator.ts +36 -6
- package/src/domains/context/codewiki/indexer.ts +59 -19
- package/src/domains/context/contract.ts +6 -2
- package/src/domains/context/extension.ts +72 -10
- package/src/domains/context/fingerprint.ts +39 -34
- package/src/domains/context/index.ts +7 -1
- package/src/domains/context/prompt-context.ts +55 -14
- package/src/domains/context/refresh.ts +9 -57
- package/src/domains/context/wiki/assemble.ts +14 -10
- package/src/domains/context/wiki/evidence.ts +209 -0
- package/src/domains/context/wiki/generate.ts +201 -67
- package/src/domains/context/wiki/meta.ts +10 -2
- package/src/domains/context/wiki/plan-store.ts +70 -14
- package/src/domains/context/wiki/plan.ts +71 -14
- package/src/domains/context/wiki/prompts.ts +42 -1
- package/src/domains/context/wiki/source-content.ts +106 -0
- package/src/domains/context/wiki/staleness.ts +33 -22
- package/src/domains/context/working-set/contract.ts +8 -2
- package/src/domains/context/working-set/engine.ts +17 -4
- package/src/domains/context/working-set/fold.ts +15 -2
- package/src/domains/context/working-set/marker.ts +2 -1
- package/src/domains/context/working-set/project.ts +18 -7
- package/src/domains/context/working-set/recall.ts +82 -56
- package/src/domains/dispatch/active-route-planner.ts +6 -3
- package/src/domains/dispatch/admission-queue.ts +19 -7
- package/src/domains/dispatch/admission.ts +3 -3
- package/src/domains/dispatch/budget-envelope.ts +47 -82
- package/src/domains/dispatch/capacity-lease.ts +57 -19
- package/src/domains/dispatch/contract.ts +10 -2
- package/src/domains/dispatch/event-pump.ts +28 -7
- package/src/domains/dispatch/execution-role.ts +49 -2
- package/src/domains/dispatch/execution-scheduler.ts +2 -0
- package/src/domains/dispatch/extension.ts +190 -105
- package/src/domains/dispatch/fleet-run.ts +20 -0
- package/src/domains/dispatch/gate-role-prompts.ts +4 -2
- package/src/domains/dispatch/parallel-writers.ts +34 -0
- package/src/domains/dispatch/reservation-store.ts +8 -34
- package/src/domains/dispatch/route-approval.ts +3 -3
- package/src/domains/dispatch/route-observer.ts +4 -2
- package/src/domains/dispatch/route-quality.ts +6 -1
- package/src/domains/dispatch/types.ts +4 -3
- package/src/domains/dispatch/worker-spawn.ts +58 -21
- package/src/domains/dispatch/workspace-checkpoint.ts +57 -0
- package/src/domains/eval/compare/behavioral.ts +81 -14
- package/src/domains/eval/compare/compare.ts +15 -5
- package/src/domains/eval/compare/envelope.ts +12 -5
- package/src/domains/eval/metrics/context.ts +24 -1
- package/src/domains/eval/metrics/tracked.ts +4 -28
- package/src/domains/eval/reports/comparison.ts +9 -9
- package/src/domains/eval/runners/clio-run.ts +5 -1
- package/src/domains/eval/schema/suite.ts +2 -0
- package/src/domains/eval/schema/validate.ts +1 -0
- package/src/domains/eval/suites/run.ts +189 -13
- package/src/domains/eval/verifiers/integrity.ts +39 -0
- package/src/domains/eval/verifiers/patch.ts +58 -2
- package/src/domains/eval/workspaces/temp-copy.ts +3 -0
- package/src/domains/evidence/build.ts +4 -2
- package/src/domains/interop/registry.ts +2 -2
- package/src/domains/middleware/hooks-io.ts +45 -26
- package/src/domains/middleware/hooks.ts +6 -0
- package/src/domains/middleware/injection-screen.ts +23 -0
- package/src/domains/middleware/rules.ts +5 -1
- package/src/domains/middleware/stalled-turn.ts +18 -3
- package/src/domains/middleware/task-board-reminder.ts +4 -2
- package/src/domains/middleware/task-nudge.ts +4 -1
- package/src/domains/mux/contract.ts +34 -1
- package/src/domains/mux/dock-controller.ts +8 -1
- package/src/domains/mux/index.ts +1 -0
- package/src/domains/mux/socket-client.ts +13 -3
- package/src/domains/observability/contract.ts +2 -2
- package/src/domains/observability/projection.ts +30 -9
- package/src/domains/prompts/compiler.ts +10 -2
- package/src/domains/prompts/contract.ts +7 -4
- package/src/domains/prompts/extension.ts +28 -64
- package/src/domains/prompts/fragments/identity/clio.md +23 -0
- package/src/domains/prompts/fragments/operating/contract.md +10 -0
- package/src/domains/prompts/fragments/operating/delegation.md +5 -0
- package/src/domains/prompts/fragments/wiki/page.md +28 -15
- package/src/domains/prompts/fragments/wiki/plan.md +4 -4
- package/src/domains/prompts/preload-prefix.ts +31 -0
- package/src/domains/prompts/preload.ts +135 -61
- package/src/domains/providers/auth/backend-file.ts +15 -11
- package/src/domains/providers/auth/storage.ts +3 -5
- package/src/domains/providers/catalog.ts +18 -3
- package/src/domains/providers/runtime-resolution.ts +11 -9
- package/src/domains/providers/runtimes/cloud/openrouter.ts +2 -0
- package/src/domains/resources/skills/promotion.ts +8 -1
- package/src/domains/safety/action-classifier.ts +9 -0
- package/src/domains/safety/autonomy.ts +10 -1
- package/src/domains/safety/contract.ts +5 -1
- package/src/domains/safety/default-path-policy.ts +11 -0
- package/src/domains/safety/extension.ts +11 -2
- package/src/domains/safety/policy-engine.ts +189 -32
- package/src/domains/safety/project-policy.ts +7 -2
- package/src/domains/safety/workspace-trust.ts +43 -0
- package/src/domains/session/compaction/compact.ts +384 -21
- package/src/domains/session/compaction/cut-point.ts +42 -5
- package/src/domains/session/compaction/tokens.ts +9 -1
- package/src/domains/session/decision-board.ts +43 -33
- package/src/domains/session/entries.ts +169 -4
- package/src/domains/session/prompt-manifest.ts +47 -8
- package/src/domains/session/task-board.ts +21 -3
- package/src/domains/user-tasks/handoff.ts +16 -0
- package/src/engine/acp/adapter.ts +44 -12
- package/src/engine/acp/server.ts +1 -0
- package/src/engine/acp/transport.ts +2 -1
- package/src/engine/acp/types.ts +6 -1
- package/src/engine/antigravity/subprocess-runtime.ts +20 -4
- package/src/engine/api-registry.ts +19 -2
- package/src/engine/apis/openai-completions.ts +13 -6
- package/src/engine/apis/output-budget.ts +26 -10
- package/src/engine/claude/sdk-runtime.ts +4 -3
- package/src/engine/env-api-keys.ts +2 -1
- package/src/engine/external-subprocess.ts +14 -3
- package/src/engine/loop-guard.ts +19 -2
- package/src/engine/provider-diagnostics.ts +129 -0
- package/src/engine/provider-payload.ts +3 -1
- package/src/engine/worker-runtime.ts +13 -2
- package/src/engine/worker-tools.ts +5 -1
- package/src/entry/extension-reload.ts +1 -0
- package/src/entry/orchestrator.ts +53 -15
- package/src/interactive/chat-loop-messages.ts +12 -4
- package/src/interactive/chat-loop.ts +115 -45
- package/src/interactive/chat-renderer.ts +60 -0
- package/src/interactive/context-recall-command.ts +2 -1
- package/src/interactive/dispatch-board.ts +17 -2
- package/src/interactive/editor-submit.ts +13 -0
- package/src/interactive/interactive-application.ts +8 -2
- package/src/interactive/interactive-event-projection.ts +7 -1
- package/src/interactive/interactive-presentation.ts +15 -7
- package/src/interactive/interactive-slash-runtime.ts +2 -0
- package/src/interactive/layout.ts +2 -1
- package/src/interactive/model-session-replay.ts +2 -2
- package/src/interactive/overlay-frame.ts +1 -0
- package/src/interactive/overlay-general-openers.ts +3 -1
- package/src/interactive/overlay-session-lifecycle.ts +6 -0
- package/src/interactive/overlays/ask-user.ts +1 -0
- package/src/interactive/overlays/message-picker.ts +1 -1
- package/src/interactive/renderers/tool-execution.ts +17 -1
- package/src/interactive/renderers/worker-entry.ts +25 -10
- package/src/interactive/slash-commands.ts +9 -7
- package/src/interactive/turn-context.ts +221 -53
- package/src/interactive/turn-middleware.ts +3 -1
- package/src/interactive/turn-persistence.ts +3 -0
- package/src/interactive/turn-runtime.ts +11 -2
- package/src/interactive/turn-state.ts +10 -9
- package/src/interactive/watch-pane.ts +18 -4
- package/src/interactive/worker-stream.ts +7 -7
- package/src/tools/agent-tools.ts +6 -3
- package/src/tools/bash.ts +1 -1
- package/src/tools/builtin-tool-catalog.ts +9 -2
- package/src/tools/codewiki/code-nav.ts +4 -10
- package/src/tools/compete-judge-task.ts +71 -0
- package/src/tools/compete-worktrees.ts +34 -0
- package/src/tools/context/index.ts +32 -7
- package/src/tools/context/surface.ts +15 -4
- package/src/tools/decide.ts +1 -1
- package/src/tools/dispatch-admission.ts +12 -1
- package/src/tools/dispatch-arguments.ts +38 -1
- package/src/tools/dispatch-plan.ts +7 -7
- package/src/tools/dispatch-runner.ts +48 -32
- package/src/tools/dispatch-schema.ts +30 -23
- package/src/tools/dispatch-scout-admission.ts +10 -44
- package/src/tools/dispatch-scout.ts +2 -3
- package/src/tools/find.ts +13 -4
- package/src/tools/grep.ts +13 -1
- package/src/tools/ls.ts +7 -1
- package/src/tools/monitor.ts +26 -11
- package/src/tools/network-policy.ts +11 -24
- package/src/tools/observation.ts +39 -2
- package/src/tools/read.ts +112 -15
- package/src/tools/registry.ts +54 -17
- package/src/tools/result-shaping.ts +110 -2
- package/src/tools/tasks.ts +33 -7
- package/src/tools/verify/frontend.ts +67 -30
- package/src/tools/verify/numeric.ts +6 -1
- package/src/tools/web-fetch-network.ts +179 -0
- package/src/tools/web-fetch-surface.ts +2 -1
- package/src/tools/web-fetch.ts +15 -13
- package/src/tools/worker-evidence.ts +27 -0
- package/src/worker/spec-contract.ts +12 -8
- package/dist/builtins-WGALA46I.js +0 -22
- package/dist/chunk-2WZ546HR.js +0 -792
- package/dist/chunk-5PSMVOLM.js +0 -56
- package/dist/chunk-EL24TAU4.js +0 -1560
- package/dist/chunk-IZXGRF7P.js +0 -4048
- package/dist/chunk-JVCV3ICN.js +0 -47
- package/dist/chunk-MNJGS2IN.js +0 -33
- package/dist/chunk-O5CVSAG5.js +0 -122
- package/dist/chunk-ODGTEFFI.js +0 -50
- package/dist/chunk-OQE5J4C6.js +0 -73
- package/dist/chunk-UUVG37B4.js +0 -244
- package/dist/chunk-V6HJFQZE.js +0 -228
- package/dist/clio-QLICPCF5.js +0 -25
- package/dist/configure-VEPX4NMX.js +0 -55
- package/dist/context-clear-S4ZJCQUX.js +0 -182
- package/dist/detail-A7JAVSIG.js +0 -98
- package/dist/evidence-4F5USFKH.js +0 -208
- package/dist/fleet-view-MN2VG4MR.js +0 -101
- package/dist/inventory-C26CFDRR.js +0 -101
- package/dist/preload-P6DGH2PZ.js +0 -13
- package/dist/slash-commands-ZXPJD64J.js +0 -92
- package/dist/tasks-IPAGMEIX.js +0 -36
- package/dist/tools-EFFEAIDP.js +0 -28
- package/dist/verify-FWYGPKMR.js +0 -29
- package/dist/wiki-generate-743CIGJW.js +0 -476
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { mkdirSync, readdirSync, rmdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
|
+
import { INSTRUCTION_SHAPED_WARNING } from "../core/untrusted-content.js";
|
|
4
5
|
import { clioStateDir } from "../core/xdg.js";
|
|
5
6
|
import type { ToolInvokeOptions, ToolResult, ToolResultDetails, ToolSpec } from "./registry.js";
|
|
6
7
|
import {
|
|
@@ -24,7 +25,10 @@ const RESULT_OFFLOAD_MAX_BYTES = 10 * 1024 * 1024;
|
|
|
24
25
|
const TAIL_NOTICE_RESERVE_BYTES = 512;
|
|
25
26
|
export const TOOL_OFFLOAD_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1000;
|
|
26
27
|
|
|
27
|
-
type ToolResultShapeContext = Pick<
|
|
28
|
+
type ToolResultShapeContext = Pick<
|
|
29
|
+
ToolInvokeOptions,
|
|
30
|
+
"sessionId" | "toolCallId" | "toolResultMaxBytes" | "supportsImages"
|
|
31
|
+
>;
|
|
28
32
|
|
|
29
33
|
function mergeDetails(details: ToolResultDetails | undefined, resultSize: Record<string, unknown>): ToolResultDetails {
|
|
30
34
|
return { ...(details ?? {}), resultSize };
|
|
@@ -419,7 +423,7 @@ function withOffloadMetadata(
|
|
|
419
423
|
* Apply legacy shaping or one declared canonical disposition. Registry calls
|
|
420
424
|
* this once, after middleware annotations have produced the terminal result.
|
|
421
425
|
*/
|
|
422
|
-
|
|
426
|
+
function shapeTextToolResultBody(
|
|
423
427
|
spec: ToolSpec,
|
|
424
428
|
result: ToolResult,
|
|
425
429
|
context?: ToolResultShapeContext,
|
|
@@ -519,3 +523,107 @@ export function shapeToolResult(
|
|
|
519
523
|
modelContext: projection.text,
|
|
520
524
|
};
|
|
521
525
|
}
|
|
526
|
+
|
|
527
|
+
/** Keep the harness warning visible even when the chosen projection omits the source body. */
|
|
528
|
+
function shapeTextToolResult(
|
|
529
|
+
spec: ToolSpec,
|
|
530
|
+
result: ToolResult,
|
|
531
|
+
context?: ToolResultShapeContext,
|
|
532
|
+
requestedDisposition?: ToolResultDisposition,
|
|
533
|
+
): ToolResult {
|
|
534
|
+
const shaped = shapeTextToolResultBody(spec, result, context, requestedDisposition);
|
|
535
|
+
const warning = `[middleware:warn] ${INSTRUCTION_SHAPED_WARNING}`;
|
|
536
|
+
if (!resultText(result).includes(warning)) return shaped;
|
|
537
|
+
const hardMaxBytes = maxBytesFor(spec, context);
|
|
538
|
+
const disposition = normalizeToolResultDisposition(spec, hardMaxBytes, requestedDisposition);
|
|
539
|
+
const preserve = (text: string, cap: number, tail: boolean): string => {
|
|
540
|
+
if (text.startsWith(warning) && byteLength(text) <= cap) return text;
|
|
541
|
+
const prefix = `${warning}\n\n`;
|
|
542
|
+
const remainder = text.split(warning).join("").trimStart();
|
|
543
|
+
const allowance = Math.max(0, cap - byteLength(prefix));
|
|
544
|
+
if (allowance === 0) return truncateUtf8(warning, cap, "");
|
|
545
|
+
const body = tail
|
|
546
|
+
? truncateTail(remainder, { maxBytes: allowance, maxLines: Number.MAX_SAFE_INTEGER }).content
|
|
547
|
+
: truncateUtf8(remainder, allowance, "");
|
|
548
|
+
return prefix + body;
|
|
549
|
+
};
|
|
550
|
+
const output = preserve(
|
|
551
|
+
resultText(shaped),
|
|
552
|
+
Math.min(hardMaxBytes, disposition?.presentation.maxBytes ?? hardMaxBytes),
|
|
553
|
+
disposition?.presentation.overflow === "tail",
|
|
554
|
+
);
|
|
555
|
+
const modelContext =
|
|
556
|
+
shaped.modelContext === undefined
|
|
557
|
+
? undefined
|
|
558
|
+
: preserve(
|
|
559
|
+
shaped.modelContext,
|
|
560
|
+
Math.min(hardMaxBytes, disposition?.context.maxBytes ?? hardMaxBytes),
|
|
561
|
+
disposition?.context.mode === "bounded" && disposition.context.excerpt === "tail",
|
|
562
|
+
);
|
|
563
|
+
const previous = existingDisposition(shaped.details);
|
|
564
|
+
const details = { ...shaped.details };
|
|
565
|
+
if (previous !== null)
|
|
566
|
+
details.resultDisposition = {
|
|
567
|
+
...previous,
|
|
568
|
+
presentation: { ...previous.presentation, content: output },
|
|
569
|
+
displayedBytes: byteLength(output),
|
|
570
|
+
contextBytes: byteLength(modelContext ?? output),
|
|
571
|
+
presentationTruncated: previous.presentationTruncated || byteLength(resultText(shaped)) > byteLength(output),
|
|
572
|
+
contextTruncated:
|
|
573
|
+
previous.contextTruncated || byteLength(shaped.modelContext ?? "") > byteLength(modelContext ?? ""),
|
|
574
|
+
};
|
|
575
|
+
const size = detailsRecord(shaped.details, "resultSize");
|
|
576
|
+
if (size !== null) details.resultSize = { ...size, shownBytes: byteLength(output) };
|
|
577
|
+
return {
|
|
578
|
+
...shaped,
|
|
579
|
+
...(shaped.kind === "ok" ? { output } : { message: output }),
|
|
580
|
+
...(modelContext === undefined ? {} : { modelContext }),
|
|
581
|
+
details,
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/** Image bytes share the same payload cap as text, including after annotation. */
|
|
586
|
+
export function shapeToolResult(
|
|
587
|
+
spec: ToolSpec,
|
|
588
|
+
result: ToolResult,
|
|
589
|
+
context?: ToolResultShapeContext,
|
|
590
|
+
requestedDisposition?: ToolResultDisposition,
|
|
591
|
+
): ToolResult {
|
|
592
|
+
if (result.kind !== "ok" || !result.images?.length)
|
|
593
|
+
return shapeTextToolResult(spec, result, context, requestedDisposition);
|
|
594
|
+
const hardMaxBytes = maxBytesFor(spec, context);
|
|
595
|
+
const disposition = normalizeToolResultDisposition(spec, hardMaxBytes, requestedDisposition);
|
|
596
|
+
const maxBytes = Math.min(hardMaxBytes, disposition?.context.maxBytes ?? hardMaxBytes);
|
|
597
|
+
const images: NonNullable<typeof result.images> = [];
|
|
598
|
+
let imageBytes = 0;
|
|
599
|
+
for (const image of result.images) {
|
|
600
|
+
const bytes = byteLength(image.data);
|
|
601
|
+
if (
|
|
602
|
+
context?.supportsImages === true &&
|
|
603
|
+
disposition?.context.mode !== "metadata-only" &&
|
|
604
|
+
bytes + imageBytes < maxBytes - 512
|
|
605
|
+
) {
|
|
606
|
+
images.push(image);
|
|
607
|
+
imageBytes += bytes;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const omitted = result.images.length - images.length;
|
|
611
|
+
const notice =
|
|
612
|
+
omitted > 0 ? `[${omitted} image(s) omitted: model capability, context policy, or tool result byte cap.]\n` : "";
|
|
613
|
+
const remaining = Math.max(1, maxBytes - imageBytes);
|
|
614
|
+
const shaped = shapeTextToolResult(
|
|
615
|
+
spec,
|
|
616
|
+
{ ...result, output: notice + result.output, images },
|
|
617
|
+
{ ...context, toolResultMaxBytes: remaining },
|
|
618
|
+
requestedDisposition,
|
|
619
|
+
);
|
|
620
|
+
if (shaped.kind !== "ok") return shaped;
|
|
621
|
+
// Legacy truncation notices may extend beyond their text allowance; the image
|
|
622
|
+
// envelope has a strict combined cap, so bound the final projections too.
|
|
623
|
+
return {
|
|
624
|
+
...shaped,
|
|
625
|
+
images,
|
|
626
|
+
output: truncateUtf8(shaped.output, remaining, ""),
|
|
627
|
+
...(shaped.modelContext === undefined ? {} : { modelContext: truncateUtf8(shaped.modelContext, remaining, "") }),
|
|
628
|
+
};
|
|
629
|
+
}
|
package/src/tools/tasks.ts
CHANGED
|
@@ -47,7 +47,8 @@ function waitingTrailer(tasks: ReadonlyArray<UserTask>): string[] {
|
|
|
47
47
|
.filter((task) => task.status === "open" || task.status === "handed")
|
|
48
48
|
.map(
|
|
49
49
|
(task) =>
|
|
50
|
-
`operator tasks waiting: ${task.id} ${JSON.stringify(task.title)} —
|
|
50
|
+
`operator tasks waiting: ${task.id} ${JSON.stringify(task.title)} — durable status=${task.status}; ` +
|
|
51
|
+
`not completed; pick only if this is the intended operator task, with action="pick" id="${task.id}" before work`,
|
|
51
52
|
);
|
|
52
53
|
}
|
|
53
54
|
|
|
@@ -60,13 +61,30 @@ function renderTaskBoardText(board: TaskBoardSnapshot, userTasks: ReadonlyArray<
|
|
|
60
61
|
if (task.status === "blocked" && task.reason) line += ` — blocked: ${task.reason}`;
|
|
61
62
|
if (task.status === "cancelled" && task.reason) line += ` — dropped: ${task.reason}`;
|
|
62
63
|
lines.push(line);
|
|
63
|
-
const
|
|
64
|
+
const operatorTask = userTasks.find((item) => item.id === task.userTaskId);
|
|
65
|
+
if (task.userTaskId) {
|
|
66
|
+
lines.push(
|
|
67
|
+
` operator task ${task.userTaskId}: durable status=${operatorTask?.status ?? "unavailable"}; ` +
|
|
68
|
+
`session=${operatorTask?.handedSessionId ?? "unlinked"}; board task=${operatorTask?.boardTaskId ?? "unlinked"}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
const outputs = operatorTask?.acceptance?.expectedOutputs;
|
|
64
72
|
if (outputs?.length) lines.push(` expected outputs: ${outputs.join(", ")}`);
|
|
65
|
-
for (const item of task.requiredValidationEvidence ?? [])
|
|
66
|
-
|
|
73
|
+
for (const item of task.requiredValidationEvidence ?? []) {
|
|
74
|
+
if (item.status === "required") {
|
|
75
|
+
lines.push(
|
|
76
|
+
` acceptance requirement: ${item.command} (${item.notes}; declaration only; execution status is in verification receipts)`,
|
|
77
|
+
);
|
|
78
|
+
} else {
|
|
79
|
+
lines.push(` acceptance: ${item.command} (${item.status}; ${item.notes})`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
67
82
|
}
|
|
68
83
|
if (counts.open > 0 && counts.active === 0) {
|
|
69
|
-
lines.push(
|
|
84
|
+
lines.push(
|
|
85
|
+
`next: start only an authorized task with action="start" before working it; ` +
|
|
86
|
+
`block proposed implementation with a note naming the pending operator decision, or drop it, and wait`,
|
|
87
|
+
);
|
|
70
88
|
}
|
|
71
89
|
lines.push(...waitingTrailer(userTasks));
|
|
72
90
|
return lines.join("\n");
|
|
@@ -145,7 +163,12 @@ export function createTasksTool(deps: TasksToolDeps): ToolSpec {
|
|
|
145
163
|
"pick moves one operator task uN onto the board; start marks one task active (the current focus); " +
|
|
146
164
|
"done completes a task (started or still pending) and requires note as the " +
|
|
147
165
|
"evidence the work actually finished; block parks it with a required reason; drop cancels it; list shows the board. " +
|
|
148
|
-
"
|
|
166
|
+
"For an operator handoff, pick the intended uN before work and use its returned linked tN; CLI hand alone does not pick it. " +
|
|
167
|
+
"Never pick unrelated inbox tasks. Before claiming operator completion, list and confirm the linked board row is completed " +
|
|
168
|
+
"and the durable operator status is done with the same session/board link; report those IDs and actual states. " +
|
|
169
|
+
"Work that did not happen is blocked or dropped, never done. A self-created plan is not operator authorization. " +
|
|
170
|
+
"For proposal-only work, block deferred implementation with note naming the pending operator decision, or drop it; " +
|
|
171
|
+
"wait for an explicit operator go-ahead before start or implementation. A skill-install choice does not grant that go-ahead.",
|
|
149
172
|
parameters: Type.Object({
|
|
150
173
|
action: StringEnum(TASKS_ACTIONS, { description: "Board action." }),
|
|
151
174
|
title: Type.Optional(Type.String({ description: "Board title (plan)." })),
|
|
@@ -192,7 +215,10 @@ export function createTasksTool(deps: TasksToolDeps): ToolSpec {
|
|
|
192
215
|
if (typedAction === "list") {
|
|
193
216
|
const board = deps.board.snapshot();
|
|
194
217
|
if (!board) {
|
|
195
|
-
const output = [
|
|
218
|
+
const output = [
|
|
219
|
+
'no task board yet; for an operator handoff, pick the intended uN before work; otherwise declare one with action="plan"',
|
|
220
|
+
...waitingTrailer(userTasks),
|
|
221
|
+
].join("\n");
|
|
196
222
|
return {
|
|
197
223
|
kind: "ok",
|
|
198
224
|
output,
|
|
@@ -3,10 +3,12 @@ import { tmpdir } from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { pathToFileURL } from "node:url";
|
|
5
5
|
import { Script } from "node:vm";
|
|
6
|
+
import { prepareBoundedImage } from "../../core/file-references.js";
|
|
6
7
|
import { combineSafeOutput, runCommandVector } from "../../core/safe-exec.js";
|
|
8
|
+
import type { ImageContent } from "../../engine/types.js";
|
|
7
9
|
import { escapeRegExp } from "../ignore-policy.js";
|
|
8
10
|
import { resolveReadPath } from "../path-utils.js";
|
|
9
|
-
import type { ToolResult, ToolResultDetails } from "../registry.js";
|
|
11
|
+
import type { ToolInvokeOptions, ToolResult, ToolResultDetails } from "../registry.js";
|
|
10
12
|
import { maxOutputArg, timeoutArg } from "../safe-exec.js";
|
|
11
13
|
import { truncateUtf8 } from "../truncate-utf8.js";
|
|
12
14
|
import { BROWSER_MODES } from "./surface.js";
|
|
@@ -25,6 +27,9 @@ interface FrontendCheck {
|
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
interface ValidationOptions {
|
|
30
|
+
supportsImages?: boolean;
|
|
31
|
+
imageMaxBytes?: number;
|
|
32
|
+
images?: ImageContent[];
|
|
28
33
|
timeoutMs: number;
|
|
29
34
|
maxOutputBytes: number;
|
|
30
35
|
signal?: AbortSignal;
|
|
@@ -84,7 +89,7 @@ const JAVASCRIPT_TYPES = new Set([
|
|
|
84
89
|
*/
|
|
85
90
|
export async function runFrontendCheck(
|
|
86
91
|
args: Record<string, unknown>,
|
|
87
|
-
options?:
|
|
92
|
+
options?: ToolInvokeOptions,
|
|
88
93
|
): Promise<ToolResult> {
|
|
89
94
|
const pathArg = typeof args.path === "string" ? args.path.trim() : "";
|
|
90
95
|
if (pathArg.length === 0) return { kind: "error", message: "verify: check=frontend requires a path argument" };
|
|
@@ -106,6 +111,9 @@ export async function runFrontendCheck(
|
|
|
106
111
|
const validateOptions: ValidationOptions = {
|
|
107
112
|
timeoutMs: timeoutArg(args),
|
|
108
113
|
maxOutputBytes: maxOutputArg(args),
|
|
114
|
+
supportsImages: options?.supportsImages === true,
|
|
115
|
+
imageMaxBytes: Math.min(maxOutputArg(args), options?.toolResultMaxBytes ?? 50_000) - 4096,
|
|
116
|
+
images: [],
|
|
109
117
|
};
|
|
110
118
|
if (options?.signal !== undefined) validateOptions.signal = options.signal;
|
|
111
119
|
|
|
@@ -131,7 +139,7 @@ export async function runFrontendCheck(
|
|
|
131
139
|
details,
|
|
132
140
|
};
|
|
133
141
|
}
|
|
134
|
-
return { kind: "ok", output, details };
|
|
142
|
+
return { kind: "ok", output, details, ...(validateOptions.images?.length ? { images: validateOptions.images } : {}) };
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
async function validateArtifact(
|
|
@@ -550,38 +558,67 @@ async function validateBrowserLoad(
|
|
|
550
558
|
});
|
|
551
559
|
return;
|
|
552
560
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
561
|
+
// A DOM dump duplicates the complete artifact on stdout. Large, otherwise
|
|
562
|
+
// valid pages then trip the diagnostic output cap. A private screenshot
|
|
563
|
+
// proves that the browser rendered without charging page bytes to that cap.
|
|
564
|
+
// Vision-capable routes retain bounded pixels before the scratch cleanup.
|
|
565
|
+
const dir = mkdtempSync(path.join(tmpdir(), "clio-coder-browser-check-"));
|
|
566
|
+
const screenshot = path.join(dir, "loaded.png");
|
|
567
|
+
try {
|
|
568
|
+
const result = await runCommandVector(
|
|
569
|
+
browser,
|
|
570
|
+
[
|
|
571
|
+
"--headless=new",
|
|
572
|
+
"--disable-gpu",
|
|
573
|
+
"--no-sandbox",
|
|
574
|
+
"--disable-dev-shm-usage",
|
|
575
|
+
`--user-data-dir=${path.join(dir, "profile")}`,
|
|
576
|
+
`--screenshot=${screenshot}`,
|
|
577
|
+
pathToFileURL(artifactPath).href,
|
|
578
|
+
],
|
|
579
|
+
{
|
|
580
|
+
timeoutMs: options.timeoutMs,
|
|
581
|
+
maxOutputBytes: options.maxOutputBytes,
|
|
582
|
+
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
583
|
+
},
|
|
584
|
+
);
|
|
585
|
+
let failure: string;
|
|
586
|
+
if (result.aborted) failure = "headless browser aborted";
|
|
587
|
+
else if (result.timedOut) failure = `headless browser timed out after ${options.timeoutMs}ms`;
|
|
588
|
+
else if (result.outputCapped) failure = `headless browser output exceeded ${options.maxOutputBytes} bytes`;
|
|
589
|
+
else if (result.exitCode !== 0) {
|
|
590
|
+
failure = `headless browser exited with ${result.exitCode ?? result.signal ?? "unknown"}`;
|
|
591
|
+
} else if (!existsSync(screenshot) || !statSync(screenshot).isFile() || statSync(screenshot).size === 0) {
|
|
592
|
+
failure = "headless browser exited without a rendered screenshot";
|
|
593
|
+
} else {
|
|
594
|
+
if (options.supportsImages) {
|
|
595
|
+
const image = await prepareBoundedImage(readFileSync(screenshot), options.imageMaxBytes ?? 0);
|
|
596
|
+
if (image) options.images?.push(image);
|
|
597
|
+
else
|
|
598
|
+
checks.push({
|
|
599
|
+
name: "browser image",
|
|
600
|
+
status: "warn",
|
|
601
|
+
message: "Screenshot omitted: could not encode within the tool result byte cap.",
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
checks.push({
|
|
605
|
+
name: "browser load",
|
|
606
|
+
status: "pass",
|
|
607
|
+
message: `loaded and rendered with ${path.basename(browser)}`,
|
|
608
|
+
path: artifactPath,
|
|
609
|
+
});
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const output = truncateUtf8(combineSafeOutput(result).trim(), 800, " [truncated]");
|
|
570
613
|
checks.push({
|
|
571
614
|
name: "browser load",
|
|
572
|
-
status: "
|
|
573
|
-
message:
|
|
615
|
+
status: "fail",
|
|
616
|
+
message: `${failure}${output ? `: ${output}` : ""}`,
|
|
574
617
|
path: artifactPath,
|
|
575
618
|
});
|
|
576
|
-
|
|
619
|
+
} finally {
|
|
620
|
+
rmSync(dir, { recursive: true, force: true });
|
|
577
621
|
}
|
|
578
|
-
const output = truncateUtf8(combineSafeOutput(result).trim(), 800, " [truncated]");
|
|
579
|
-
checks.push({
|
|
580
|
-
name: "browser load",
|
|
581
|
-
status: "fail",
|
|
582
|
-
message: `headless browser exited with ${result.exitCode ?? result.signal ?? "unknown"}${output ? `: ${output}` : ""}`,
|
|
583
|
-
path: artifactPath,
|
|
584
|
-
});
|
|
585
622
|
}
|
|
586
623
|
|
|
587
624
|
function parseAttributes(source: string): Record<string, string> {
|
|
@@ -156,7 +156,12 @@ export function parseNumericPayload(text: string, label: string): NumericPayload
|
|
|
156
156
|
function deviation(actual: number, expected: number, index?: number): NumericDeviation {
|
|
157
157
|
const finite = Number.isFinite(actual) && Number.isFinite(expected);
|
|
158
158
|
const absolute = finite ? Math.abs(actual - expected) : Number.POSITIVE_INFINITY;
|
|
159
|
-
|
|
159
|
+
let relative = !finite ? null : expected === 0 ? (absolute === 0 ? 0 : null) : absolute / Math.abs(expected);
|
|
160
|
+
if (finite && !Number.isFinite(absolute)) {
|
|
161
|
+
// Finite subtraction overflows only across signs, where division first
|
|
162
|
+
// is safe. Keep subtraction first for nearby values to preserve precision.
|
|
163
|
+
relative = Math.abs(actual / expected - 1);
|
|
164
|
+
}
|
|
160
165
|
return {
|
|
161
166
|
...(index !== undefined ? { index } : {}),
|
|
162
167
|
actual,
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { lookup } from "node:dns/promises";
|
|
2
|
+
import { request as httpRequest } from "node:http";
|
|
3
|
+
import { request as httpsRequest } from "node:https";
|
|
4
|
+
import { BlockList, isIP } from "node:net";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { createBrotliDecompress, createGunzip, createInflate } from "node:zlib";
|
|
7
|
+
import { WEB_FETCH_ALLOW_PRIVATE_NETWORK_ENV } from "./network-policy.js";
|
|
8
|
+
|
|
9
|
+
const blocked = new BlockList();
|
|
10
|
+
for (const [address, prefix] of [
|
|
11
|
+
["0.0.0.0", 8],
|
|
12
|
+
["10.0.0.0", 8],
|
|
13
|
+
["100.64.0.0", 10],
|
|
14
|
+
["127.0.0.0", 8],
|
|
15
|
+
["169.254.0.0", 16],
|
|
16
|
+
["172.16.0.0", 12],
|
|
17
|
+
["192.168.0.0", 16],
|
|
18
|
+
["192.0.0.0", 24],
|
|
19
|
+
["192.0.2.0", 24],
|
|
20
|
+
["198.18.0.0", 15],
|
|
21
|
+
["198.51.100.0", 24],
|
|
22
|
+
["203.0.113.0", 24],
|
|
23
|
+
["224.0.0.0", 4],
|
|
24
|
+
["240.0.0.0", 4],
|
|
25
|
+
] as const)
|
|
26
|
+
blocked.addSubnet(address, prefix, "ipv4");
|
|
27
|
+
// Permit only global unicast IPv6. Block transition mechanisms that can embed
|
|
28
|
+
// an IPv4 destination and local/documentation allocations within that range.
|
|
29
|
+
for (const [address, prefix] of [
|
|
30
|
+
["2001::", 32],
|
|
31
|
+
["2001:db8::", 32],
|
|
32
|
+
["2002::", 16],
|
|
33
|
+
] as const)
|
|
34
|
+
blocked.addSubnet(address, prefix, "ipv6");
|
|
35
|
+
const globalV6 = new BlockList();
|
|
36
|
+
globalV6.addSubnet("2000::", 3, "ipv6");
|
|
37
|
+
export function isPublicWebAddress(address: string): boolean {
|
|
38
|
+
const family = isIP(address);
|
|
39
|
+
if (family === 4) return !blocked.check(address, "ipv4");
|
|
40
|
+
return family === 6 && globalV6.check(address, "ipv6") && !blocked.check(address, "ipv6");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export class WebFetchNetworkError extends Error {
|
|
44
|
+
constructor(message: string) {
|
|
45
|
+
super(`WEB_FETCH_PRIVATE_NETWORK: ${message}`);
|
|
46
|
+
this.name = "WebFetchNetworkError";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
interface Address {
|
|
51
|
+
address: string;
|
|
52
|
+
family: number;
|
|
53
|
+
}
|
|
54
|
+
export interface WebFetchNetworkDependencies {
|
|
55
|
+
resolve?: (hostname: string) => Promise<Address[]>;
|
|
56
|
+
request?: (url: URL, init: RequestInit, address: Address) => Promise<Response>;
|
|
57
|
+
allowPrivateNetwork?: boolean;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Pin the checked address in the socket lookup while retaining the URL host
|
|
61
|
+
* for Host, TLS SNI and certificate verification. No second DNS resolution,
|
|
62
|
+
* proxy, pooled socket, or automatic redirect can bypass admission. */
|
|
63
|
+
async function requestPinnedWebUrl(url: URL, init: RequestInit, address: Address): Promise<Response> {
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
const headers = new Headers(init.headers);
|
|
66
|
+
headers.delete("host");
|
|
67
|
+
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(
|
|
68
|
+
url,
|
|
69
|
+
{
|
|
70
|
+
method: init.method ?? "GET",
|
|
71
|
+
headers: Object.fromEntries(headers),
|
|
72
|
+
agent: false,
|
|
73
|
+
...(init.signal ? { signal: init.signal } : {}),
|
|
74
|
+
lookup: (_hostname, options, callback) => {
|
|
75
|
+
if (options.all) callback(null, [address]);
|
|
76
|
+
else callback(null, address.address, address.family);
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
(response) => {
|
|
80
|
+
const responseHeaders = new Headers();
|
|
81
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
82
|
+
if (value !== undefined) responseHeaders.set(key, Array.isArray(value) ? value.join(", ") : value);
|
|
83
|
+
}
|
|
84
|
+
const status = response.statusCode ?? 500;
|
|
85
|
+
let stream: Readable = response;
|
|
86
|
+
const encoding = responseHeaders.get("content-encoding");
|
|
87
|
+
const decoder =
|
|
88
|
+
encoding === "gzip"
|
|
89
|
+
? createGunzip()
|
|
90
|
+
: encoding === "br"
|
|
91
|
+
? createBrotliDecompress()
|
|
92
|
+
: encoding === "deflate"
|
|
93
|
+
? createInflate()
|
|
94
|
+
: null;
|
|
95
|
+
if (decoder) {
|
|
96
|
+
response.on("error", (error) => decoder.destroy(error));
|
|
97
|
+
decoder.on("close", () => response.destroy());
|
|
98
|
+
stream = response.pipe(decoder);
|
|
99
|
+
responseHeaders.delete("content-encoding");
|
|
100
|
+
responseHeaders.delete("content-length");
|
|
101
|
+
}
|
|
102
|
+
const noBody = init.method === "HEAD" || [204, 205, 304].includes(status);
|
|
103
|
+
if (noBody) response.resume();
|
|
104
|
+
const result = new Response(noBody ? null : (Readable.toWeb(stream) as ReadableStream<Uint8Array>), {
|
|
105
|
+
status,
|
|
106
|
+
statusText: response.statusMessage ?? "",
|
|
107
|
+
headers: responseHeaders,
|
|
108
|
+
});
|
|
109
|
+
Object.defineProperty(result, "url", { value: url.toString() });
|
|
110
|
+
resolve(result);
|
|
111
|
+
},
|
|
112
|
+
);
|
|
113
|
+
request.on("error", reject);
|
|
114
|
+
request.end(typeof init.body === "string" ? init.body : undefined);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** DNS lookup itself is not cancellable; stop awaiting it on turn cancellation. */
|
|
119
|
+
async function abortableLookup(
|
|
120
|
+
pending: Promise<Address[]>,
|
|
121
|
+
signal: AbortSignal | null | undefined,
|
|
122
|
+
): Promise<Address[]> {
|
|
123
|
+
if (!signal) return pending;
|
|
124
|
+
signal.throwIfAborted();
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
const onAbort = (): void => reject(signal.reason);
|
|
127
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
128
|
+
pending.then(resolve, reject).finally(() => signal.removeEventListener("abort", onAbort));
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** Every hop, including helper URLs, resolves and validates before connecting. */
|
|
133
|
+
export async function fetchWebUrl(
|
|
134
|
+
input: string | URL,
|
|
135
|
+
initial: RequestInit = {},
|
|
136
|
+
dependencies: WebFetchNetworkDependencies = {},
|
|
137
|
+
): Promise<Response> {
|
|
138
|
+
let url = new URL(input);
|
|
139
|
+
const init = { ...initial, headers: new Headers(initial.headers) };
|
|
140
|
+
const allowPrivate = dependencies.allowPrivateNetwork ?? process.env[WEB_FETCH_ALLOW_PRIVATE_NETWORK_ENV] === "1";
|
|
141
|
+
for (let hop = 0; hop <= 10; hop++) {
|
|
142
|
+
init.signal?.throwIfAborted();
|
|
143
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password)
|
|
144
|
+
throw new Error("web_fetch: unsupported URL scheme or embedded credentials");
|
|
145
|
+
const hostname = url.hostname.replace(/^\[|\]$/g, "");
|
|
146
|
+
const addresses = isIP(hostname)
|
|
147
|
+
? [{ address: hostname, family: isIP(hostname) }]
|
|
148
|
+
: await abortableLookup((dependencies.resolve ?? ((host) => lookup(host, { all: true })))(hostname), init.signal);
|
|
149
|
+
init.signal?.throwIfAborted();
|
|
150
|
+
const address = addresses[0];
|
|
151
|
+
if (address === undefined) throw new Error("web_fetch: DNS returned no addresses");
|
|
152
|
+
if (!allowPrivate && addresses.some((address) => !isPublicWebAddress(address.address)))
|
|
153
|
+
throw new WebFetchNetworkError(
|
|
154
|
+
`destination ${url.hostname} is not public; operator opt-in ${WEB_FETCH_ALLOW_PRIVATE_NETWORK_ENV}=1 is required`,
|
|
155
|
+
);
|
|
156
|
+
const response = await (dependencies.request ?? requestPinnedWebUrl)(url, init, address);
|
|
157
|
+
const location = response.headers.get("location");
|
|
158
|
+
if (![301, 302, 303, 307, 308].includes(response.status) || location === null) return response;
|
|
159
|
+
await response.body?.cancel();
|
|
160
|
+
if (hop === 10) throw new Error("web_fetch: too many redirects");
|
|
161
|
+
const next = new URL(location, url);
|
|
162
|
+
if (next.origin !== url.origin) {
|
|
163
|
+
// Custom headers can carry credentials too. A cross-origin redirect gets
|
|
164
|
+
// no caller headers; the target still receives the ordinary Host header.
|
|
165
|
+
init.headers = new Headers();
|
|
166
|
+
}
|
|
167
|
+
if (
|
|
168
|
+
(response.status === 303 && init.method !== "HEAD") ||
|
|
169
|
+
([301, 302].includes(response.status) && init.method === "POST")
|
|
170
|
+
) {
|
|
171
|
+
init.method = "GET";
|
|
172
|
+
delete init.body;
|
|
173
|
+
init.headers.delete("content-type");
|
|
174
|
+
init.headers.delete("content-length");
|
|
175
|
+
}
|
|
176
|
+
url = next;
|
|
177
|
+
}
|
|
178
|
+
throw new Error("web_fetch: too many redirects");
|
|
179
|
+
}
|
|
@@ -4,7 +4,8 @@ import type { ToolSurface } from "./lazy-tool.js";
|
|
|
4
4
|
|
|
5
5
|
export const webFetchToolSurface = {
|
|
6
6
|
name: ToolNames.WebFetch,
|
|
7
|
-
description:
|
|
7
|
+
description:
|
|
8
|
+
"Fetch an http(s) URL; HTML is cleaned and converted to Markdown. Non-2xx responses are errors. Non-GET/HEAD methods or any body require outward-action approval; private networks require operator opt-in.",
|
|
8
9
|
parameters: Type.Object({
|
|
9
10
|
url: Type.String({ description: "Fully-qualified http(s) URL." }),
|
|
10
11
|
method: Type.Optional(Type.String({ description: "HTTP method (default GET)." })),
|
package/src/tools/web-fetch.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { UNTRUSTED_CONTENT_BANNER } from "../core/untrusted-content.js";
|
|
1
2
|
import type { ToolResult, ToolSpec } from "./registry.js";
|
|
2
3
|
import { truncateUtf8 } from "./truncate-utf8.js";
|
|
4
|
+
import { fetchWebUrl } from "./web-fetch-network.js";
|
|
3
5
|
import { webFetchToolSurface } from "./web-fetch-surface.js";
|
|
4
6
|
|
|
5
7
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
@@ -374,7 +376,7 @@ async function fetchArxivPaperSummary(
|
|
|
374
376
|
maxBytes: number,
|
|
375
377
|
): Promise<ToolResult | null> {
|
|
376
378
|
const metadataUrl = `https://export.arxiv.org/api/query?id_list=${encodeURIComponent(paperId)}`;
|
|
377
|
-
const response = await
|
|
379
|
+
const response = await fetchWebUrl(metadataUrl, init);
|
|
378
380
|
if (response.status < 200 || response.status >= 300) return null;
|
|
379
381
|
const read = await readResponseText(response, Math.min(120_000, maxBytes));
|
|
380
382
|
const entry = /<entry\b[^>]*>([\s\S]*?)<\/entry>/i.exec(read.text)?.[1];
|
|
@@ -384,7 +386,7 @@ async function fetchArxivPaperSummary(
|
|
|
384
386
|
let alphaxivRead: ReadResult | null = null;
|
|
385
387
|
const alphaUrl = `https://alphaxiv.org/overview/${encodeURIComponent(paperId)}.md`;
|
|
386
388
|
try {
|
|
387
|
-
const alpha = await
|
|
389
|
+
const alpha = await fetchWebUrl(alphaUrl, init);
|
|
388
390
|
if (alpha.status >= 200 && alpha.status < 300) {
|
|
389
391
|
alphaxivRead = await readResponseText(alpha, Math.min(80_000, Math.max(0, maxBytes - read.bytesRead)));
|
|
390
392
|
if (alphaxivRead.text.trim().length > 0) paper.alphaxivOverview = alphaxivRead.text.trim();
|
|
@@ -416,7 +418,7 @@ async function fetchArxivPaperSummary(
|
|
|
416
418
|
const bytesRead = read.bytesRead + (alphaxivRead?.bytesRead ?? 0);
|
|
417
419
|
return {
|
|
418
420
|
kind: "ok",
|
|
419
|
-
output: truncate(lines.join("\n")
|
|
421
|
+
output: truncate(`${UNTRUSTED_CONTENT_BANNER}\n${lines.join("\n")}`, maxBytes),
|
|
420
422
|
details: {
|
|
421
423
|
url: `https://arxiv.org/abs/${paper.id}`,
|
|
422
424
|
status: 200,
|
|
@@ -437,7 +439,7 @@ async function fetchArxivApiSummary(
|
|
|
437
439
|
init: Parameters<typeof fetch>[1],
|
|
438
440
|
maxBytes: number,
|
|
439
441
|
): Promise<ToolResult | null> {
|
|
440
|
-
const response = await
|
|
442
|
+
const response = await fetchWebUrl(url, init);
|
|
441
443
|
if (response.status < 200 || response.status >= 300) return null;
|
|
442
444
|
const read = await readResponseText(response, Math.min(240_000, maxBytes));
|
|
443
445
|
const entries = Array.from(read.text.matchAll(/<entry\b[^>]*>([\s\S]*?)<\/entry>/gi))
|
|
@@ -469,7 +471,7 @@ async function fetchArxivApiSummary(
|
|
|
469
471
|
}
|
|
470
472
|
return {
|
|
471
473
|
kind: "ok",
|
|
472
|
-
output: truncate(lines.join("\n")
|
|
474
|
+
output: truncate(`${UNTRUSTED_CONTENT_BANNER}\n${lines.join("\n")}`, maxBytes),
|
|
473
475
|
details: {
|
|
474
476
|
url: url.toString(),
|
|
475
477
|
status: 200,
|
|
@@ -553,7 +555,7 @@ async function fetchRepoTreeSummary(
|
|
|
553
555
|
init: Parameters<typeof fetch>[1],
|
|
554
556
|
maxBytes: number,
|
|
555
557
|
): Promise<ToolResult | null> {
|
|
556
|
-
const apiResponse = await
|
|
558
|
+
const apiResponse = await fetchWebUrl(target.apiUrl, init);
|
|
557
559
|
if (apiResponse.status < 200 || apiResponse.status >= 300) return null;
|
|
558
560
|
const apiRead = await readResponseText(apiResponse, Math.min(200_000, maxBytes));
|
|
559
561
|
let entries: unknown[];
|
|
@@ -581,7 +583,7 @@ async function fetchRepoTreeSummary(
|
|
|
581
583
|
for (const file of files) {
|
|
582
584
|
if (remaining <= 2000) break;
|
|
583
585
|
const rawUrl = `${target.rawBaseUrl}/${file}`;
|
|
584
|
-
const rawResponse = await
|
|
586
|
+
const rawResponse = await fetchWebUrl(rawUrl, init);
|
|
585
587
|
if (rawResponse.status < 200 || rawResponse.status >= 300) continue;
|
|
586
588
|
const rawRead = await readResponseText(rawResponse, Math.min(80_000, remaining));
|
|
587
589
|
sections.push("", `--- ${file} ---`, rawRead.text.trim());
|
|
@@ -589,7 +591,7 @@ async function fetchRepoTreeSummary(
|
|
|
589
591
|
}
|
|
590
592
|
return {
|
|
591
593
|
kind: "ok",
|
|
592
|
-
output: truncate(sections.join("\n")
|
|
594
|
+
output: truncate(`${UNTRUSTED_CONTENT_BANNER}\n${sections.join("\n")}`, maxBytes),
|
|
593
595
|
details: {
|
|
594
596
|
url: target.apiUrl,
|
|
595
597
|
status: 200,
|
|
@@ -621,7 +623,7 @@ function formatOutput(args: {
|
|
|
621
623
|
if (args.extracted.description) lines.push(`Description: ${args.extracted.description}`);
|
|
622
624
|
if (args.extracted.canonical) lines.push(`Canonical: ${args.extracted.canonical}`);
|
|
623
625
|
lines.push("", "Content:", args.extracted.content || "[empty]");
|
|
624
|
-
return truncate(lines.join("\n")
|
|
626
|
+
return truncate(`${UNTRUSTED_CONTENT_BANNER}\n${lines.join("\n")}`, args.maxBytes);
|
|
625
627
|
}
|
|
626
628
|
|
|
627
629
|
export const webFetchTool: ToolSpec = {
|
|
@@ -683,10 +685,10 @@ export const webFetchTool: ToolSpec = {
|
|
|
683
685
|
method,
|
|
684
686
|
headers,
|
|
685
687
|
signal: controller.signal,
|
|
686
|
-
redirect: "
|
|
688
|
+
redirect: "manual",
|
|
687
689
|
};
|
|
688
690
|
if (body !== undefined) init.body = body;
|
|
689
|
-
if (method === "GET" && body === undefined && format !== "raw") {
|
|
691
|
+
if (method === "GET" && body === undefined && format !== "raw" && Object.keys(userHeaders).length === 0) {
|
|
690
692
|
if (arxivApiUrl(parsed)) {
|
|
691
693
|
const arxivApiSummary = await fetchArxivApiSummary(parsed, init, maxBytes);
|
|
692
694
|
if (arxivApiSummary) return arxivApiSummary;
|
|
@@ -702,7 +704,7 @@ export const webFetchTool: ToolSpec = {
|
|
|
702
704
|
if (repoSummary) return repoSummary;
|
|
703
705
|
}
|
|
704
706
|
}
|
|
705
|
-
const response = await
|
|
707
|
+
const response = await fetchWebUrl(parsed, init);
|
|
706
708
|
const contentType = headerValue(response, "content-type");
|
|
707
709
|
const readLimit =
|
|
708
710
|
response.status >= 200 && response.status < 300 ? maxBytes : Math.min(ERROR_PREVIEW_BYTES, maxBytes);
|
|
@@ -711,7 +713,7 @@ export const webFetchTool: ToolSpec = {
|
|
|
711
713
|
const preview = extractWebFetchContent(read.text, contentType, response.url || parsed.toString(), "auto").content;
|
|
712
714
|
return {
|
|
713
715
|
kind: "error",
|
|
714
|
-
message: `web_fetch: HTTP ${response.status}: ${response.statusText}${preview ? `\nPreview:\n${truncate(preview, ERROR_PREVIEW_BYTES)}` : ""}`,
|
|
716
|
+
message: `web_fetch: HTTP ${response.status}: ${response.statusText}${preview ? `\n${UNTRUSTED_CONTENT_BANNER}\nPreview:\n${truncate(preview, ERROR_PREVIEW_BYTES)}` : ""}`,
|
|
715
717
|
};
|
|
716
718
|
}
|
|
717
719
|
if (isProbablyBinary(contentType, read.text)) {
|