@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.
- package/CHANGELOG.md +82 -0
- package/README.md +7 -6
- package/dist/{acp-JWPQZM2D.js → acp-ZWZCPS2A.js} +13 -13
- package/dist/{agents-4GCDIRVX.js → agents-LYSOWZUE.js} +53 -52
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-SYAKTDQE.js → auth-WBQGKWQ5.js} +27 -27
- package/dist/{background-OW67WMYR.js → background-BUMOBAQN.js} +4 -4
- package/dist/{builtins-TKS63VNV.js → builtins-ODRJOEDI.js} +7 -7
- package/dist/{chunk-JLBVCROW.js → chunk-2DRRZ57Q.js} +33 -24
- package/dist/chunk-2JBZYUPY.js +105 -0
- package/dist/chunk-2KUBKL63.js +336 -0
- package/dist/{chunk-K45LHSCI.js → chunk-2VBWFXYE.js} +7 -3
- package/dist/{chunk-XTLJDC2X.js → chunk-2X2R3UTH.js} +23 -18
- package/dist/{chunk-5HULHKT2.js → chunk-37LW32LZ.js} +5 -5
- package/dist/{chunk-W7KNI3F5.js → chunk-3AND2EFU.js} +5 -5
- package/dist/{chunk-36XSBPXL.js → chunk-3RDHGNU7.js} +95 -27
- package/dist/{chunk-BIY22UUK.js → chunk-3SUDBGEI.js} +11 -10
- package/dist/{chunk-3IQOZRQ6.js → chunk-3TQN67I2.js} +7 -7
- package/dist/{chunk-KWJXCL2X.js → chunk-3U4BL2EV.js} +3 -3
- package/dist/{chunk-RBES4TCZ.js → chunk-3UQADNG2.js} +3 -3
- package/dist/{chunk-V4ZKOKRB.js → chunk-434LRQ6Z.js} +61 -53
- package/dist/{chunk-MWMW53WW.js → chunk-4ATBOFRP.js} +649 -193
- package/dist/{chunk-QGIC5SX5.js → chunk-4DNL43EZ.js} +3 -3
- package/dist/{chunk-GVU4CXPJ.js → chunk-4HFJKRGZ.js} +113 -54
- package/dist/{chunk-5A6XR3RJ.js → chunk-555E2WVV.js} +16 -2
- package/dist/{chunk-LZDLYSUN.js → chunk-5RTEFNBP.js} +3 -3
- package/dist/{chunk-HMGAKB7E.js → chunk-64XJW7NT.js} +15 -15
- package/dist/{chunk-EXKUF426.js → chunk-7FBCRWVT.js} +280 -280
- package/dist/{chunk-K3W6BF5C.js → chunk-7JSOSVLP.js} +2 -2
- package/dist/{chunk-WFTSK7N3.js → chunk-7N3OLLSL.js} +4 -4
- package/dist/{chunk-JRA6OBHY.js → chunk-A6DULIMH.js} +17 -5
- package/dist/{chunk-R5NRX5N4.js → chunk-AB3QXXBC.js} +2 -2
- package/dist/chunk-ACCECAH4.js +49 -0
- package/dist/{chunk-GJBJHJNY.js → chunk-AM6CEP2K.js} +5 -5
- package/dist/{chunk-MUXNDNMZ.js → chunk-AY4XE6GN.js} +19 -13
- package/dist/{chunk-MATCRH3M.js → chunk-BBA2TAWV.js} +9 -9
- package/dist/{chunk-PMUUAABD.js → chunk-BMNVVKEW.js} +9 -9
- package/dist/{chunk-TOPICHGR.js → chunk-CTGZCEI6.js} +2 -2
- package/dist/{chunk-L75H5B3B.js → chunk-DIAJYJYG.js} +2 -2
- package/dist/{chunk-JIMWEYWO.js → chunk-EHZRAB4U.js} +2 -2
- package/dist/{chunk-YXANQGCX.js → chunk-EM2DIQAJ.js} +6 -6
- package/dist/{chunk-JCVIL6TY.js → chunk-ETF4ROKH.js} +4 -4
- package/dist/{chunk-5W4FRA5Q.js → chunk-F2YM3JY4.js} +483 -253
- package/dist/{chunk-YGIV24MF.js → chunk-FEBQWHJT.js} +21 -16
- package/dist/{chunk-PGEFOTJB.js → chunk-FPS4R2RN.js} +5 -4
- package/dist/{chunk-XC5POIL4.js → chunk-G5R53COU.js} +1 -1
- package/dist/chunk-GHXGMFQ5.js +40 -0
- package/dist/{chunk-QLKCCC2J.js → chunk-GJDRMBDI.js} +14 -14
- package/dist/{chunk-2ZWLMA3T.js → chunk-GREYLTZ5.js} +7 -7
- package/dist/{chunk-YXFKLMX2.js → chunk-H2WSCZZT.js} +22 -6
- package/dist/{chunk-FNVPQQYT.js → chunk-H6IUCY6Q.js} +2 -2
- package/dist/{chunk-5C2OQHLR.js → chunk-H72DCH3E.js} +92 -203
- package/dist/{chunk-JYKUMHCQ.js → chunk-H7TXJR23.js} +21 -21
- package/dist/chunk-HBJQQTKM.js +40 -0
- package/dist/chunk-HCVKSGNZ.js +990 -0
- package/dist/{chunk-ARRUMZ7X.js → chunk-I47EJPYL.js} +3 -3
- package/dist/{chunk-YKIIWURD.js → chunk-IALGWTLO.js} +3 -3
- package/dist/{chunk-FB3KTE2J.js → chunk-IALZJE37.js} +4 -4
- package/dist/{chunk-RAUOKUZV.js → chunk-IC7JXLOM.js} +15 -10
- package/dist/{chunk-LLCGGVSW.js → chunk-IOSVTTCD.js} +7 -7
- package/dist/{chunk-DBREN25X.js → chunk-IPTPMLA6.js} +8 -3
- package/dist/{chunk-V552WL53.js → chunk-IZZI3SKQ.js} +3 -67
- package/dist/{chunk-UDAK6GR2.js → chunk-JIYWMQZ5.js} +2 -2
- package/dist/{chunk-O3HSB2YL.js → chunk-JKU34ACI.js} +2 -2
- package/dist/{chunk-6X7VOCDY.js → chunk-JTR3VSV3.js} +3 -3
- package/dist/{chunk-O2QJDRWP.js → chunk-JU6MAMRJ.js} +4 -4
- package/dist/chunk-JURMQWVJ.js +15 -0
- package/dist/{chunk-STC6CWUZ.js → chunk-K3XN4LZ4.js} +5 -5
- package/dist/{chunk-ATB3Q7YO.js → chunk-KIVFXGBM.js} +27 -2
- package/dist/{chunk-WJWNZXRM.js → chunk-KOAHT3N2.js} +2 -2
- package/dist/chunk-KP5BPXR3.js +73 -0
- package/dist/{chunk-K53E2PTW.js → chunk-KRJQG47M.js} +3 -3
- package/dist/{chunk-IILXVWJY.js → chunk-KW6OJ7IY.js} +19 -21
- package/dist/{chunk-A46ILRS2.js → chunk-L3NBWLSN.js} +4 -4
- package/dist/{chunk-2U2U5POA.js → chunk-L4RUTLRL.js} +5 -5
- package/dist/{chunk-QYSAZMSH.js → chunk-LGTVWPRN.js} +2 -2
- package/dist/{chunk-KGP3UQGJ.js → chunk-LSQW6KZO.js} +5 -5
- package/dist/{chunk-P4JS3MH5.js → chunk-LWJYOHT3.js} +8 -8
- package/dist/{chunk-U3TPUXOQ.js → chunk-M6YLF66Z.js} +74 -40
- package/dist/{chunk-5D2FNBMG.js → chunk-MJ4QEJVT.js} +2 -2
- package/dist/{chunk-RM3XJX7P.js → chunk-MO65K5CH.js} +5 -5
- package/dist/{chunk-H5DPSUBB.js → chunk-MTOZEQHL.js} +3 -3
- package/dist/{chunk-6R5MBXBJ.js → chunk-NBPA5QM6.js} +2 -2
- package/dist/{chunk-H77XBUBM.js → chunk-NMBEW4PP.js} +3 -3
- package/dist/{chunk-QWUSS2QP.js → chunk-NPLLK3HO.js} +67 -87
- package/dist/{chunk-K5UJD6MM.js → chunk-NSYGPIVW.js} +5 -5
- package/dist/{context-EZZPT2ZV.js → chunk-NXTV5OI5.js} +30 -84
- package/dist/{chunk-F7Y6QTPL.js → chunk-NYDG4QP4.js} +4 -4
- package/dist/{chunk-PFZJMXIY.js → chunk-OA2GDACN.js} +2 -2
- package/dist/{chunk-Q32C6AWI.js → chunk-PJI57EC6.js} +4 -4
- package/dist/{chunk-EFXMQYI6.js → chunk-PJJBUGMR.js} +52 -52
- package/dist/{chunk-ICYIUNO4.js → chunk-PNJE7JPS.js} +18 -3
- package/dist/chunk-PP23PZEV.js +1347 -0
- package/dist/chunk-PPIFDSBK.js +409 -0
- package/dist/{chunk-RFULVPBX.js → chunk-PTFISXQO.js} +6 -5
- package/dist/{chunk-JV25I7ID.js → chunk-QB33Z5S7.js} +5 -5
- package/dist/{chunk-D55WO5J7.js → chunk-QGNII5VC.js} +8 -8
- package/dist/{chunk-RKFNU5UA.js → chunk-QI72X67S.js} +104 -27
- package/dist/chunk-QKHZZFKH.js +98 -0
- package/dist/{chunk-5UG6EZI3.js → chunk-RDKX2PME.js} +4 -4
- package/dist/{chunk-B5ZTR6KZ.js → chunk-RL7LJYN4.js} +1 -1
- package/dist/{chunk-BE4I3UJ2.js → chunk-RQROVOV3.js} +15 -13
- package/dist/{chunk-TEHVMHOK.js → chunk-S34A7BSP.js} +3 -3
- package/dist/{chunk-4P6M2TTE.js → chunk-SJETVJHX.js} +2 -2
- package/dist/{chunk-OPC4DQD6.js → chunk-SJMNU4ZS.js} +2 -2
- package/dist/{chunk-2JSCCEKO.js → chunk-SLLG2G44.js} +2 -2
- package/dist/{chunk-EPYATQMG.js → chunk-SQAZN2V3.js} +42 -16
- package/dist/{chunk-E2NSPYLC.js → chunk-SQBT46OF.js} +5 -5
- package/dist/{chunk-WTZVSMQZ.js → chunk-TCUOGIL2.js} +5 -5
- package/dist/{chunk-RRZFRIJP.js → chunk-TIWPKCVO.js} +5 -5
- package/dist/{chunk-QLAGXTTV.js → chunk-UIU7MGZ3.js} +5 -1
- package/dist/{chunk-WLHX3MM5.js → chunk-V4XJWDHR.js} +21 -11
- package/dist/{chunk-PJ5H5B7A.js → chunk-VPWGADBG.js} +18 -18
- package/dist/{chunk-GEYX2NZ5.js → chunk-VWFCAK34.js} +6 -6
- package/dist/{chunk-44U2OUSM.js → chunk-W72LLZAV.js} +2 -2
- package/dist/{chunk-ORRNGQDV.js → chunk-WGRDABW7.js} +4 -4
- package/dist/{chunk-RNLAPBJL.js → chunk-XFLSL7BT.js} +2 -2
- package/dist/{chunk-2SXGG2IV.js → chunk-XJZEDCNT.js} +6 -6
- package/dist/{chunk-UB33F3YW.js → chunk-XLLEL3K7.js} +5 -5
- package/dist/{chunk-2GPGAE5W.js → chunk-XNIZBOFV.js} +15 -1
- package/dist/{chunk-WS4FOGLY.js → chunk-XNZWWDC3.js} +2 -2
- package/dist/{chunk-P7GTE4FX.js → chunk-XRECG65F.js} +2 -2
- package/dist/chunk-XTQ7MEJG.js +457 -0
- package/dist/{chunk-GEVQNST4.js → chunk-XZWSP67B.js} +2 -2
- package/dist/{chunk-OEMFEL26.js → chunk-Y3M2T5RO.js} +3 -3
- package/dist/{chunk-HP7KJ5O2.js → chunk-YPQOPFP7.js} +6 -6
- package/dist/{chunk-MEHBW2SP.js → chunk-YQYINEJI.js} +6 -6
- package/dist/{chunk-RXI7K4J5.js → chunk-ZF6CV4WZ.js} +1338 -217
- package/dist/{chunk-3XE4NRLF.js → chunk-ZKJU55MX.js} +4 -2
- package/dist/{chunk-526ABLHD.js → chunk-ZKQ63XZ5.js} +12 -35
- package/dist/{chunk-PAQVETLA.js → chunk-ZKVMDNAN.js} +5 -5
- package/dist/cli/index.js +47 -37
- package/dist/{clio-BPBAPZGA.js → clio-JUDCLNHC.js} +7 -7
- package/dist/clio-context-tools-FT672MNZ.js +136 -0
- package/dist/{code-nav-KBQ3RIFK.js → code-nav-7OVCTP2Z.js} +28 -26
- package/dist/{components-6DKAXWFN.js → components-OZXZMDWU.js} +5 -5
- package/dist/{config-FWL5JK2H.js → config-P3ZQVF63.js} +80 -75
- package/dist/{config-graph-ACDB26L2.js → config-graph-GKAOBAS5.js} +74 -70
- package/dist/{configure-ZIZ4YV62.js → configure-25LRYZJG.js} +45 -44
- package/dist/context-72VQV7JX.js +73 -0
- package/dist/{context-VIL5MFRH.js → context-COWRWXP3.js} +74 -70
- package/dist/{context-Z3GOBHDK.js → context-WB3D474G.js} +12 -12
- package/dist/{context-clear-ZPB3L7MN.js → context-clear-Y4LYMWC6.js} +70 -66
- package/dist/{context-working-set-2GLBVF7L.js → context-working-set-TMZYVC7A.js} +15 -14
- package/dist/data-tool-KMBWKKWR.js +2987 -0
- package/dist/{detail-VSBWYSGZ.js → detail-4GLROGY5.js} +71 -67
- package/dist/{dispatch-runner-EEEHGKX4.js → dispatch-runner-TR3LBP5P.js} +92 -88
- package/dist/{docs-VMMWFVHL.js → docs-ZK777W2G.js} +3 -3
- package/dist/{doctor-V5L4IQGP.js → doctor-WC4OV2OB.js} +61 -59
- package/dist/{eval-VJYJ2BV3.js → eval-FUNWJNUJ.js} +45 -45
- package/dist/{evals-J2H5V6DD.js → evals-L73EBHSU.js} +4 -4
- package/dist/{evidence-Y35YSXH6.js → evidence-AVJ2RTHX.js} +80 -76
- package/dist/{evidence-POWAEBEW.js → evidence-P4NZOAK7.js} +70 -66
- package/dist/{evidence-XCCCLS36.js → evidence-Y55WKYHH.js} +79 -75
- package/dist/{evolve-GPG72VB6.js → evolve-MAWKRYWF.js} +75 -71
- package/dist/{extensions-YIZ7W3DA.js → extensions-PYQH3H47.js} +8 -8
- package/dist/{fleet-2MDCQ2VK.js → fleet-M4H2QBWT.js} +84 -80
- package/dist/{fleet-W2AF3TOJ.js → fleet-ULBXXRDR.js} +123 -119
- package/dist/{fleet-commands-WS56G26H.js → fleet-commands-7NNC4JZU.js} +17 -16
- package/dist/{fleet-decisions-MYGZ3JW7.js → fleet-decisions-EHEY7KPU.js} +9 -9
- package/dist/{fleet-graph-ELTBXBAV.js → fleet-graph-LQ2AHZT3.js} +15 -15
- package/dist/{fleet-inspect-45IK73L4.js → fleet-inspect-5IGBIIYZ.js} +76 -72
- package/dist/{fleet-preflight-T5NCZKHE.js → fleet-preflight-UTTNOKMG.js} +7 -2
- package/dist/{fleet-validate-VG4JBLA4.js → fleet-validate-YGILJKA6.js} +20 -20
- package/dist/{fleet-verify-VTSABAYO.js → fleet-verify-AUWTCDKR.js} +70 -66
- package/dist/{fleet-view-XC7WMKSS.js → fleet-view-TGUFCY5A.js} +73 -69
- package/dist/{init-VTJNNTIP.js → init-GFN2Z7NF.js} +94 -90
- package/dist/{interop-IU6BNA7C.js → interop-EF5JUWWK.js} +21 -21
- package/dist/{inventory-QPQUTUUZ.js → inventory-I6VJDDYF.js} +73 -69
- package/dist/{library-Q3NWL5CM.js → library-3J5IO2OJ.js} +13 -13
- package/dist/{library-LF7DLU6S.js → library-IJTOFTDS.js} +16 -15
- package/dist/{library-HUTAS57T.js → library-Z3KZSHPE.js} +27 -27
- package/dist/{library-import-PPW4YUC5.js → library-import-IMKFLDHX.js} +21 -21
- package/dist/{library-inventory-DIRVFRZU.js → library-inventory-CQP5D6GU.js} +13 -13
- package/dist/{library-validation-XHUZ3INE.js → library-validation-33UTX7AI.js} +11 -11
- package/dist/mcp-5FWZKUS6.js +26 -0
- package/dist/{memory-Z2LSKNV6.js → memory-36CWN67Y.js} +75 -71
- package/dist/{models-3FTREYPY.js → models-KQ6PQJJQ.js} +49 -49
- package/dist/{monitor-HF2MQRB3.js → monitor-XX6ZD6KC.js} +83 -79
- package/dist/{orchestrator-UYPA6W4S.js → orchestrator-SK6HDAOP.js} +1337 -772
- package/dist/{panes-736XB73K.js → panes-L27QRXUH.js} +12 -12
- package/dist/{panes-C4P3PIWT.js → panes-LXZIWNOZ.js} +4 -4
- package/dist/{paths-JQ4QYIYB.js → paths-7DJDU4P4.js} +5 -5
- package/dist/{preload-XSLRYH3Y.js → preload-K2TDYI4Y.js} +70 -66
- package/dist/{reset-V7QSPZYE.js → reset-73VU3XNT.js} +10 -10
- package/dist/{resources-OJGDFHYT.js → resources-3BYJYVYL.js} +16 -16
- package/dist/{run-T354SMDW.js → run-AR7PY6GW.js} +132 -128
- package/dist/run-script-H2KUDIII.js +41 -0
- package/dist/{settings-MWZXO6RV.js → settings-3VMBMWID.js} +4 -4
- package/dist/{share-Y5ZKJPND.js → share-HVWH4FPF.js} +21 -21
- package/dist/{skills-4GLZC4LN.js → skills-5TYEY75Q.js} +22 -22
- package/dist/{skills-eval-L5T7GODM.js → skills-eval-CK3MD63Z.js} +96 -87
- package/dist/{skills-inventory-LASKXEZI.js → skills-inventory-KSFYG3I6.js} +16 -16
- package/dist/{slash-commands-OIMRU36D.js → slash-commands-DMVHML7P.js} +47 -44
- package/dist/{steer-KMAM2Y2C.js → steer-XCD6V3EW.js} +4 -4
- package/dist/{support-AWC3XKPX.js → support-JAZL6VBR.js} +7 -7
- package/dist/{system-CD75NYBU.js → system-3TDQRMZZ.js} +26 -26
- package/dist/{targets-VSZX2J2S.js → targets-EZKHAYRN.js} +66 -65
- package/dist/{tasks-AN567LYH.js → tasks-SNEFHWYW.js} +12 -12
- package/dist/{terminal-lease-6KTWNHVY.js → terminal-lease-BNLFA4OF.js} +8 -7
- package/dist/{tools-AGRK3V5J.js → tools-7IM6BDCE.js} +12 -12
- package/dist/{trace-P4MQZD33.js → trace-C3MBGD4S.js} +8 -8
- package/dist/{tui-primitives-A6MUW32V.js → tui-primitives-36BY2774.js} +2 -2
- package/dist/{uninstall-BRUTEPIC.js → uninstall-WWLOSZ42.js} +10 -10
- package/dist/{upgrade-SBCGHQGJ.js → upgrade-ETK2JNSJ.js} +37 -47
- package/dist/{usage-BIDVTO6V.js → usage-S2HOB7BZ.js} +93 -89
- package/dist/{verifiers-LTGCAMXS.js → verifiers-QDTEVH7R.js} +24 -22
- package/dist/{verify-OZU4LLNP.js → verify-SUKUK6XM.js} +15 -14
- package/dist/web/client/assets/{abnfDiagram-VCTEODGH-C5wfoHm3.js → abnfDiagram-VCTEODGH-BznNOe_I.js} +1 -1
- package/dist/web/client/assets/{arc-oH91sfLl.js → arc-Pry-7G1_.js} +1 -1
- package/dist/web/client/assets/architecture-7GRP2DOG-BQO9DL_y.js +1 -0
- package/dist/web/client/assets/architectureDiagram-5GKGNRK7-CKPbdvyx.js +36 -0
- package/dist/web/client/assets/{blockDiagram-I7D4REHJ-wi0_CYHL.js → blockDiagram-I7D4REHJ-prINbpbM.js} +1 -1
- package/dist/web/client/assets/{c4Diagram-7LVT6UL2-DV7NYc2W.js → c4Diagram-7LVT6UL2-DkVRKtyU.js} +1 -1
- package/dist/web/client/assets/channel-c4EeUUqA.js +1 -0
- package/dist/web/client/assets/{chunk-4HAMMTFA-Bhsegh3F.js → chunk-4HAMMTFA-CV0Z1ApC.js} +1 -1
- package/dist/web/client/assets/{chunk-75Z2AOVW-RQCckcQG.js → chunk-75Z2AOVW-D34Nohxq.js} +1 -1
- package/dist/web/client/assets/chunk-DU6HZSFF-Das_cS-O.js +125 -0
- package/dist/web/client/assets/{chunk-F27PBJKO-BcNqv2x1.js → chunk-F27PBJKO-CmRojxkG.js} +1 -1
- package/dist/web/client/assets/{chunk-GMAD6QVW-Bq8JWiZT.js → chunk-GMAD6QVW-ClYZmc73.js} +1 -1
- package/dist/web/client/assets/{chunk-GVQU2GXP-DbchrAeJ.js → chunk-GVQU2GXP-B2BiHFt-.js} +1 -1
- package/dist/web/client/assets/{chunk-IMKFNOWR-DrpvjocK.js → chunk-IMKFNOWR-BGApZ8nP.js} +1 -1
- package/dist/web/client/assets/{chunk-L3NEJ4N5-DHLmTnCe.js → chunk-L3NEJ4N5-DIzCgpkY.js} +1 -1
- package/dist/web/client/assets/{chunk-OSK3NFVY-CsRbtN9n.js → chunk-OSK3NFVY-BPT-yePv.js} +1 -1
- package/dist/web/client/assets/{chunk-P2QGCYS3-aqPbxoMh.js → chunk-P2QGCYS3-BC1WTc2t.js} +1 -1
- package/dist/web/client/assets/{chunk-POPQ4Y6H-Dl5vw0h0.js → chunk-POPQ4Y6H-BSjzBmZU.js} +1 -1
- package/dist/web/client/assets/{chunk-PWAF6VOD-D7OBRSdO.js → chunk-PWAF6VOD-BIjLs86Z.js} +1 -1
- package/dist/web/client/assets/{chunk-SHT3W25Y-CdKCIwuB.js → chunk-SHT3W25Y-CduDz2cm.js} +1 -1
- package/dist/web/client/assets/{chunk-SVP7TREG-B94Nu_1-.js → chunk-SVP7TREG-XUn4pPAP.js} +1 -1
- package/dist/web/client/assets/{chunk-TICWLB2K-jjRQI_hk.js → chunk-TICWLB2K-DcBy2DKy.js} +1 -1
- package/dist/web/client/assets/{chunk-XXDRQBXY-azkbKE37.js → chunk-XXDRQBXY-DqAYeljN.js} +1 -1
- package/dist/web/client/assets/classDiagram-ZZMXUADV-C0HR7YKN.js +1 -0
- package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-C0HR7YKN.js +1 -0
- package/dist/web/client/assets/cose-bilkent-JH36ORCC-CVh1icwb.js +1 -0
- package/dist/web/client/assets/{cynefin-OW5HDTMX--i9RDU5f.js → cynefin-OW5HDTMX-BecPbyM6.js} +1 -1
- package/dist/web/client/assets/{cynefinDiagram-5FMLGOSQ-cRcvyBdp.js → cynefinDiagram-5FMLGOSQ-BzMzFwyT.js} +1 -1
- package/dist/web/client/assets/{dagre-GXQ25YYZ-C9mZmAPe.js → dagre-GXQ25YYZ-CAWJmRMG.js} +1 -1
- package/dist/web/client/assets/{diagram-S7CK7UJ4-Oj_zlLDY.js → diagram-S7CK7UJ4--lp0ALmn.js} +1 -1
- package/dist/web/client/assets/{diagram-UQ7AKVKN-BWKbbfcR.js → diagram-UQ7AKVKN-gKUnsjcj.js} +1 -1
- package/dist/web/client/assets/{diagram-VSXAHHWV-C3N3f7DO.js → diagram-VSXAHHWV-BoN5D1Gh.js} +1 -1
- package/dist/web/client/assets/{diagram-VX7I27RA-CtDKDAWe.js → diagram-VX7I27RA-BMtuswQ6.js} +1 -1
- package/dist/web/client/assets/{diagram-Z3DM3KII-B8bkBRCz.js → diagram-Z3DM3KII-DtU8LXrA.js} +1 -1
- package/dist/web/client/assets/dist-v5Q1xZ2K.js +1 -0
- package/dist/web/client/assets/{ebnfDiagram-PWID7BFC-CskW-Whx.js → ebnfDiagram-PWID7BFC-DDcnv9BH.js} +1 -1
- package/dist/web/client/assets/{erDiagram-RLTQ6QDP-C-83cgCW.js → erDiagram-RLTQ6QDP-DvRb4iDL.js} +1 -1
- package/dist/web/client/assets/eventmodeling-NTZA5JFV-01h4SbTc.js +1 -0
- package/dist/web/client/assets/flowDiagram-HODETNUW-Bll_YZ6T.js +1 -0
- package/dist/web/client/assets/framework-YGoR34M4.js +9 -0
- package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-DdFZ9hvH.js +292 -0
- package/dist/web/client/assets/{gitGraph-4MIJSDKK-B40cQtBE.js → gitGraph-4MIJSDKK-DjD_AAMj.js} +1 -1
- package/dist/web/client/assets/{gitGraphDiagram-WWUBYQGX-CH-7P7Di.js → gitGraphDiagram-WWUBYQGX-CDyN9n2u.js} +1 -1
- package/dist/web/client/assets/index-CVcy0FAn.js +75 -0
- package/dist/web/client/assets/{info-A6RAGUB7-eCCE9D_Q.js → info-A6RAGUB7-C_XK8Hq0.js} +1 -1
- package/dist/web/client/assets/{infoDiagram-27XIBGKW-DRnvqMjM.js → infoDiagram-27XIBGKW-DIe4tJ1i.js} +1 -1
- package/dist/web/client/assets/{ishikawaDiagram-5VMMS53U-DBA_55wp.js → ishikawaDiagram-5VMMS53U-CVl5unKI.js} +1 -1
- package/dist/web/client/assets/{journeyDiagram-3NMN7TZE-C-ewpNl7.js → journeyDiagram-3NMN7TZE-CPEB1Vt8.js} +1 -1
- package/dist/web/client/assets/{kanban-definition-UXKFOSKX-B1taGsu0.js → kanban-definition-UXKFOSKX-j-9WXjYQ.js} +1 -1
- package/dist/web/client/assets/{line-lZ0kyxDI.js → line-BIDAcEtX.js} +1 -1
- package/dist/web/client/assets/{linear-DIc8FgZj.js → linear-SzVmGSw4.js} +1 -1
- package/dist/web/client/assets/{mermaid-parser.core-SXolxpXw.js → mermaid-parser.core-Ux4vssh0.js} +3 -3
- package/dist/web/client/assets/{mermaid.core-DXgQtkNg.js → mermaid.core-CDuwVKeh.js} +4 -4
- package/dist/web/client/assets/{mindmap-definition-YA3MSWOX-DXJas9K7.js → mindmap-definition-YA3MSWOX-5MlQEeQ6.js} +1 -1
- package/dist/web/client/assets/{packet-AYTQ26CC-OqVl_07o.js → packet-AYTQ26CC-DRO66c9Q.js} +1 -1
- package/dist/web/client/assets/{pegDiagram-XKGWAZYB-CPE_zdfN.js → pegDiagram-XKGWAZYB-BakZnSjM.js} +1 -1
- package/dist/web/client/assets/{pie-WAS4IAKB-DAxnMBLe.js → pie-WAS4IAKB-BEzcmhz8.js} +1 -1
- package/dist/web/client/assets/{pieDiagram-E7YTZNPT-Uwjpufxv.js → pieDiagram-E7YTZNPT-DpmqgoPt.js} +1 -1
- package/dist/web/client/assets/prism-core-BtsZdCS6.js +1 -0
- package/dist/web/client/assets/{quadrantDiagram-AXDQQJYC-Bjs4yjgs.js → quadrantDiagram-AXDQQJYC-DuMPwwV2.js} +1 -1
- package/dist/web/client/assets/{radar-RG4KPBEZ-CuCKjHM3.js → radar-RG4KPBEZ-Djm3oXl5.js} +1 -1
- package/dist/web/client/assets/{railroad-74A4TZTK-CnQK-Cc1.js → railroad-74A4TZTK-Cpvkwsao.js} +1 -1
- package/dist/web/client/assets/railroad-abnf-HS5TGJTU-CpRQ3ruG.js +1 -0
- package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-1Rm5a5eJ.js +1 -0
- package/dist/web/client/assets/railroad-peg-WCYAUIDC-C8344cTh.js +1 -0
- package/dist/web/client/assets/{railroadDiagram-O6MQD6OU-BDDIPNLL.js → railroadDiagram-O6MQD6OU-CgMS4B6R.js} +1 -1
- package/dist/web/client/assets/{requirementDiagram-BXWQKSXE-B5Ydyxc1.js → requirementDiagram-BXWQKSXE-CX5eoNdN.js} +1 -1
- package/dist/web/client/assets/rolldown-runtime-hePW80VL.js +1 -0
- package/dist/web/client/assets/{sankeyDiagram-P5KCCOFB-Bw2Qym75.js → sankeyDiagram-P5KCCOFB-CODBX2N3.js} +1 -1
- package/dist/web/client/assets/{sequenceDiagram-WJ2MYXX4-BZf36nO0.js → sequenceDiagram-WJ2MYXX4-eUhhF8OR.js} +1 -1
- package/dist/web/client/assets/src-B6xuSHsQ.js +1 -0
- package/dist/web/client/assets/{stateDiagram-D77RDMKH-DnH6JRkp.js → stateDiagram-D77RDMKH-vR6l0NC2.js} +1 -1
- package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-BYUm8jLY.js +1 -0
- package/dist/web/client/assets/{swimlanes-42K2YHIH-D9PZmtZg.js → swimlanes-42K2YHIH-v9Tw_zX7.js} +1 -1
- package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-B2jdCvhD.js +8 -0
- package/dist/web/client/assets/{timeline-definition-24CTP7MA-CrkZZBo7.js → timeline-definition-24CTP7MA-DxianbhU.js} +1 -1
- package/dist/web/client/assets/{treeView-Q6P3EWNA-C9zDShoC.js → treeView-Q6P3EWNA-DLxnZb9R.js} +1 -1
- package/dist/web/client/assets/{treemap-WGGIJYW6-B-plj9yK.js → treemap-WGGIJYW6-I7UnZ6xJ.js} +1 -1
- package/dist/web/client/assets/{vennDiagram-4TSXK5OY-VeOdaphN.js → vennDiagram-4TSXK5OY-Ar7M8Mrj.js} +1 -1
- package/dist/web/client/assets/{wardley-WFR3VGLG-Wl1P_m6L.js → wardley-WFR3VGLG-B8ZSHeDu.js} +1 -1
- package/dist/web/client/assets/{wardleyDiagram-VM6X3IG4-B85-R9t2.js → wardleyDiagram-VM6X3IG4-Qks2FmIn.js} +1 -1
- package/dist/web/client/assets/{xychartDiagram-S5SC5T6Z-BrD8OW8m.js → xychartDiagram-S5SC5T6Z-BBBjRtiE.js} +1 -1
- package/dist/web/client/index.html +3 -1
- package/dist/web/reads-worker.js +17 -17
- package/dist/web/server.js +25 -25
- package/dist/{web-EU6ATJWA.js → web-EMGUGGEI.js} +3 -3
- package/dist/{web-fetch-U22Q7HV4.js → web-fetch-6BRRVQON.js} +22 -5
- package/dist/{wiki-generate-LZRLFG6I.js → wiki-generate-XHSJTDOP.js} +104 -100
- package/dist/{with-panes-X5CZOGML.js → with-panes-Z6BTEHMZ.js} +11 -11
- package/dist/worker/entry.js +101 -87
- package/docs/README.md +1 -1
- package/docs/architecture/artifact-placement.md +12 -1
- package/docs/architecture/library.md +1 -1
- package/docs/architecture/prompt-envelope-and-tools.md +37 -27
- package/docs/architecture/safety-model.md +19 -6
- package/docs/architecture/session-lifecycle.md +10 -4
- package/docs/architecture/tui-design.md +37 -14
- package/docs/guide/commands-and-modes.md +39 -19
- package/docs/guide/configuration-and-targets.md +7 -5
- package/docs/guide/configuration-reference.md +116 -13
- package/docs/guide/environment-variables.md +2 -5
- package/docs/guide/fleet-dispatch.md +3 -2
- package/docs/guide/glossary.md +1 -1
- package/docs/guide/installation-and-lifecycle.md +2 -2
- package/docs/guide/resource-library.md +1 -1
- package/docs/guide/tool-usage.md +166 -64
- package/docs/guide/troubleshooting.md +1 -1
- package/docs/process/documentation-guide.md +1 -0
- package/docs/process/fleet-demo-runbook.md +6 -6
- package/docs/process/scientific-validation.md +22 -2
- package/docs/process/tool-audit-v0.4.9.md +357 -0
- package/package.json +1 -1
- package/src/cli/argv.ts +31 -0
- package/src/cli/clio.ts +17 -13
- package/src/cli/config.ts +4 -0
- package/src/cli/doctor-panes.ts +1 -1
- package/src/cli/doctor.ts +3 -1
- package/src/cli/index.ts +14 -1
- package/src/cli/mcp.ts +106 -0
- package/src/cli/skills-eval.ts +8 -2
- package/src/cli/upgrade.ts +34 -38
- package/src/cli/verifiers.ts +1 -1
- package/src/core/bash-exec.ts +27 -4
- package/src/core/config.ts +2 -1
- package/src/core/defaults.ts +10 -1
- package/src/core/event-bus.ts +1 -1
- package/src/core/run-records.ts +438 -0
- package/src/core/safe-exec.ts +506 -56
- package/src/core/skill-activation.ts +5 -3
- package/src/core/termination.ts +3 -3
- package/src/core/tool-names.ts +33 -12
- package/src/domains/context/clio-md.ts +1 -1
- package/src/domains/context/worker/pressure.ts +6 -2
- package/src/domains/context/working-set/path-index.ts +7 -2
- package/src/domains/dispatch/code-step.ts +7 -2
- package/src/domains/dispatch/contract.ts +7 -0
- package/src/domains/dispatch/execution-role.ts +3 -3
- package/src/domains/dispatch/execution-scheduler.ts +204 -79
- package/src/domains/dispatch/extension.ts +131 -14
- package/src/domains/dispatch/fleet-preflight.ts +18 -3
- package/src/domains/dispatch/fleet-run.ts +1 -0
- package/src/domains/dispatch/gate-decisions.ts +3 -3
- package/src/domains/dispatch/heartbeat.ts +1 -1
- package/src/domains/dispatch/host-verification.ts +16 -14
- package/src/domains/dispatch/receipt-findings.ts +3 -4
- package/src/domains/dispatch/reservation-store.ts +7 -9
- package/src/domains/dispatch/route-facts.ts +1 -1
- package/src/domains/dispatch/state.ts +3 -3
- package/src/domains/dispatch/types.ts +1 -1
- package/src/domains/evidence/build.ts +35 -7
- package/src/domains/gateway/mcp/client.ts +923 -0
- package/src/domains/gateway/mcp/config.ts +456 -0
- package/src/domains/gateway/mcp/index.ts +88 -0
- package/src/domains/gateway/mcp/protocol.ts +273 -0
- package/src/domains/gateway/mcp/trust.ts +263 -0
- package/src/domains/lifecycle/doctor.ts +17 -3
- package/src/domains/mux/contract.ts +5 -9
- package/src/domains/mux/detect.ts +1 -1
- package/src/domains/mux/extension.ts +1 -1
- package/src/domains/mux/protocol.ts +5 -7
- package/src/domains/mux/socket-client.ts +3 -3
- package/src/domains/observability/accountability.ts +2 -2
- package/src/domains/observability/contract.ts +7 -3
- package/src/domains/observability/evidence-index.ts +2 -2
- package/src/domains/observability/projection.ts +10 -0
- package/src/domains/prompts/compiler.ts +41 -23
- package/src/domains/prompts/fragments/identity/docs-routing.md +2 -2
- package/src/domains/prompts/fragments/operating/skills.md +12 -10
- package/src/domains/providers/index.ts +5 -1
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +42 -10
- package/src/domains/providers/probe/http.ts +44 -59
- package/src/domains/providers/probe/reasoning.ts +2 -0
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +20 -31
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +9 -4
- package/src/domains/safety/action-classifier.ts +17 -1
- package/src/domains/safety/call-target.ts +14 -0
- package/src/domains/safety/contract.ts +1 -1
- package/src/domains/safety/finish-contract.ts +9 -3
- package/src/domains/safety/loop-detector.ts +1 -1
- package/src/domains/safety/policy-engine.ts +7 -0
- package/src/domains/safety/protected-artifacts.ts +3 -4
- package/src/domains/safety/rejection-feedback.ts +1 -1
- package/src/domains/safety/scope.ts +2 -3
- package/src/domains/safety/validation-contract.ts +3 -2
- package/src/domains/scheduling/budget.ts +5 -3
- package/src/domains/scheduling/contract.ts +2 -1
- package/src/domains/scheduling/extension.ts +3 -3
- package/src/domains/session/compaction/branch-summary.ts +1 -1
- package/src/domains/session/compaction/compact.ts +25 -2
- package/src/domains/session/compaction/cut-point.ts +1 -1
- package/src/domains/session/compaction/tokens.ts +5 -10
- package/src/domains/session/contract.ts +1 -1
- package/src/domains/session/cwd-fallback.ts +2 -2
- package/src/domains/session/handoff.ts +5 -1
- package/src/domains/session/history.ts +6 -0
- package/src/domains/session/manager.ts +14 -7
- package/src/domains/session/retry.ts +2 -1
- package/src/domains/session/session-artifacts.ts +12 -7
- package/src/domains/session/task-board.ts +2 -3
- package/src/engine/apis/openai-completions.ts +8 -0
- package/src/engine/loop-guard.ts +7 -0
- package/src/engine/provider-error-body.ts +65 -0
- package/src/engine/session.ts +118 -29
- package/src/engine/worker-runtime.ts +3 -0
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +18 -2
- package/src/interactive/chat-loop-policy.ts +1 -0
- package/src/interactive/chat-loop.ts +8 -4
- package/src/interactive/chat-panel.ts +23 -9
- package/src/interactive/chat-renderer.ts +33 -11
- package/src/interactive/clio-editor.ts +13 -5
- package/src/interactive/dispatch-board.ts +70 -30
- package/src/interactive/editor-submit.ts +30 -25
- package/src/interactive/footer/widgets.ts +12 -9
- package/src/interactive/interactive-presentation.ts +2 -3
- package/src/interactive/mux-bridge.ts +3 -7
- package/src/interactive/overlay-general-openers.ts +14 -7
- package/src/interactive/overlays/cwd-fallback.ts +1 -1
- package/src/interactive/overlays/library-model.ts +114 -35
- package/src/interactive/overlays/library.ts +52 -5
- package/src/interactive/overlays/list-overlay.ts +4 -1
- package/src/interactive/overlays/session-selector.ts +28 -23
- package/src/interactive/overlays/settings.ts +20 -1
- package/src/interactive/overlays/tree-selector.ts +47 -10
- package/src/interactive/panes-runtime.ts +1 -1
- package/src/interactive/renderers/compaction-summary.ts +1 -1
- package/src/interactive/renderers/provider-error.ts +118 -0
- package/src/interactive/renderers/retry-status.ts +59 -23
- package/src/interactive/renderers/tool-execution.ts +67 -7
- package/src/interactive/renderers/worker-answer.ts +198 -0
- package/src/interactive/renderers/worker-entry.ts +57 -163
- package/src/interactive/slash-commands.ts +26 -1
- package/src/interactive/slash-spec.ts +2 -2
- package/src/interactive/theme/labels.ts +66 -30
- package/src/interactive/turn-persistence.ts +6 -1
- package/src/interactive/turn-recovery.ts +2 -1
- package/src/interactive/turn-runtime.ts +22 -5
- package/src/interactive/view/artifacts.ts +3 -2
- package/src/interactive/view/view-overlay.ts +96 -20
- package/src/tools/agent-tools.ts +21 -7
- package/src/tools/artifact.ts +16 -8
- package/src/tools/bash.ts +90 -11
- package/src/tools/bootstrap.ts +42 -4
- package/src/tools/builtin-tool-catalog.ts +72 -7
- package/src/tools/context/index.ts +27 -31
- package/src/tools/context/library.ts +3 -1
- package/src/tools/context/surface.ts +12 -26
- package/src/tools/core-bootstrap.ts +72 -1
- package/src/tools/data/csv.ts +1189 -0
- package/src/tools/data/index.ts +308 -0
- package/src/tools/data/json.ts +1799 -0
- package/src/tools/data/jsonl.ts +561 -0
- package/src/tools/data/shared.ts +452 -0
- package/src/tools/edit-diff.ts +0 -7
- package/src/tools/edit.ts +115 -18
- package/src/tools/file-mutation-queue.ts +114 -4
- package/src/tools/find.ts +108 -29
- package/src/tools/gateway/caps.ts +11 -0
- package/src/tools/gateway/clio-context-surface.ts +41 -0
- package/src/tools/gateway/clio-context-tools.ts +77 -0
- package/src/tools/gateway/data-surface.ts +138 -0
- package/src/tools/gateway/data-tool.ts +201 -0
- package/src/tools/gateway/index.ts +342 -0
- package/src/tools/gateway/mcp-capabilities.ts +469 -0
- package/src/tools/grep.ts +88 -33
- package/src/tools/harness-extensions.ts +3 -0
- package/src/tools/ignore-policy.ts +7 -5
- package/src/tools/ls.ts +111 -20
- package/src/tools/policy.ts +35 -13
- package/src/tools/presentation.ts +6 -0
- package/src/tools/read.ts +634 -156
- package/src/tools/registry.ts +94 -6
- package/src/tools/run-script.ts +997 -0
- package/src/tools/spawn-hygiene.ts +157 -5
- package/src/tools/surface.ts +163 -0
- package/src/tools/verify/authoring.ts +8 -3
- package/src/tools/verify/catalog.ts +14 -1
- package/src/tools/verify/numeric.ts +367 -59
- package/src/tools/verify/perf.ts +171 -9
- package/src/tools/verify/scripts.ts +178 -26
- package/src/tools/web-fetch-surface.ts +22 -0
- package/src/tools/web-fetch.ts +26 -1
- package/src/tools/write.ts +45 -19
- package/dist/chunk-B6UM3OZC.js +0 -15
- package/dist/chunk-GJ24ODAX.js +0 -196
- package/dist/chunk-LZCCBLRC.js +0 -57
- package/dist/web/client/assets/architecture-7GRP2DOG-EGozsYEO.js +0 -1
- package/dist/web/client/assets/architectureDiagram-5GKGNRK7-z9FokbJl.js +0 -36
- package/dist/web/client/assets/channel-CiUWbHN9.js +0 -1
- package/dist/web/client/assets/chunk-DU6HZSFF-C5USiOAy.js +0 -125
- package/dist/web/client/assets/classDiagram-ZZMXUADV-CMODalmo.js +0 -1
- package/dist/web/client/assets/classDiagram-v2-VYDZK3BY-CMODalmo.js +0 -1
- package/dist/web/client/assets/cose-bilkent-JH36ORCC-RbQL23qS.js +0 -1
- package/dist/web/client/assets/dist-D0_q-A2b.js +0 -1
- package/dist/web/client/assets/eventmodeling-NTZA5JFV-DjVq8wKU.js +0 -1
- package/dist/web/client/assets/flowDiagram-HODETNUW-BUiCBGXt.js +0 -1
- package/dist/web/client/assets/ganttDiagram-EL5Y4UJY-B2lb8lvF.js +0 -292
- package/dist/web/client/assets/index-FSIC94pi.js +0 -83
- package/dist/web/client/assets/prism-core-BngLtbUd.js +0 -1
- package/dist/web/client/assets/railroad-abnf-HS5TGJTU-BcW01NZG.js +0 -1
- package/dist/web/client/assets/railroad-ebnf-LZEXJU2U-B7YCEDDd.js +0 -1
- package/dist/web/client/assets/railroad-peg-WCYAUIDC-DjNZbSTZ.js +0 -1
- package/dist/web/client/assets/src-yeptRXpt.js +0 -1
- package/dist/web/client/assets/stateDiagram-v2-MP3YSRHH-C7QtHeK4.js +0 -1
- package/dist/web/client/assets/swimlanesDiagram-VR7AAH4N-CBZlPFky.js +0 -8
|
@@ -1,33 +1,58 @@
|
|
|
1
1
|
import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
clioDocsToolSurface,
|
|
4
|
+
clioLibraryToolSurface
|
|
5
|
+
} from "./chunk-ACCECAH4.js";
|
|
2
6
|
import {
|
|
3
7
|
contextToolSurface
|
|
4
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-HBJQQTKM.js";
|
|
5
9
|
import {
|
|
6
10
|
resolveFdBinary,
|
|
7
11
|
resolveRgBinary
|
|
8
12
|
} from "./chunk-JABWPKFY.js";
|
|
9
13
|
import {
|
|
10
|
-
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
runScriptToolSurface
|
|
15
|
+
} from "./chunk-HCVKSGNZ.js";
|
|
16
|
+
import {
|
|
17
|
+
webFetchToolSurface,
|
|
18
|
+
webReadToolSurface
|
|
19
|
+
} from "./chunk-PNJE7JPS.js";
|
|
12
20
|
import {
|
|
13
21
|
verifyToolSurface
|
|
14
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-L4RUTLRL.js";
|
|
23
|
+
import {
|
|
24
|
+
dataToolSurface,
|
|
25
|
+
prepareDataAdmissionArguments
|
|
26
|
+
} from "./chunk-PPIFDSBK.js";
|
|
15
27
|
import {
|
|
16
28
|
codeNavToolSurface
|
|
17
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-TCUOGIL2.js";
|
|
30
|
+
import {
|
|
31
|
+
McpError,
|
|
32
|
+
createMcpStdioClient,
|
|
33
|
+
resolveMcpServers
|
|
34
|
+
} from "./chunk-PP23PZEV.js";
|
|
35
|
+
import {
|
|
36
|
+
incompleteInstallationAdvice
|
|
37
|
+
} from "./chunk-3A3CUMKA.js";
|
|
18
38
|
import {
|
|
19
39
|
RESPONSE_SCHEMA_RUNTIME_ID,
|
|
20
40
|
bashTool,
|
|
21
41
|
builtin,
|
|
22
42
|
createAskUserTool,
|
|
43
|
+
nestedBlockedResult,
|
|
44
|
+
nestedExecutedResult,
|
|
23
45
|
readMaxBytes,
|
|
24
46
|
readTool,
|
|
25
47
|
renderAgentLedger
|
|
26
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-4ATBOFRP.js";
|
|
27
49
|
import {
|
|
28
50
|
createTaskBoardStore,
|
|
29
51
|
taskBoardCounts
|
|
30
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-KOAHT3N2.js";
|
|
53
|
+
import {
|
|
54
|
+
hashToolCall
|
|
55
|
+
} from "./chunk-AY4XE6GN.js";
|
|
31
56
|
import {
|
|
32
57
|
isLoadableExtension
|
|
33
58
|
} from "./chunk-OH3YYA3B.js";
|
|
@@ -37,18 +62,34 @@ import {
|
|
|
37
62
|
parseExtensionManifest,
|
|
38
63
|
resolveExtensionEntrypoint
|
|
39
64
|
} from "./chunk-6TKOFFGE.js";
|
|
65
|
+
import {
|
|
66
|
+
gatewayCapabilityKind,
|
|
67
|
+
toolSpecPlacement,
|
|
68
|
+
withGatewayForCapabilities
|
|
69
|
+
} from "./chunk-2JBZYUPY.js";
|
|
40
70
|
import {
|
|
41
71
|
describeCallAction
|
|
42
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-XNIZBOFV.js";
|
|
43
73
|
import {
|
|
44
74
|
applyToolProfile
|
|
45
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-XZWSP67B.js";
|
|
76
|
+
import {
|
|
77
|
+
BusChannels
|
|
78
|
+
} from "./chunk-W5RM7YAH.js";
|
|
46
79
|
import {
|
|
47
80
|
networkToolsDisabled
|
|
48
81
|
} from "./chunk-SL2RDHKO.js";
|
|
49
82
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
83
|
+
DATA_OBSERVATION_SELF_CAP_BYTES,
|
|
84
|
+
GATEWAY_FIND_SELF_CAP_BYTES
|
|
85
|
+
} from "./chunk-JURMQWVJ.js";
|
|
86
|
+
import {
|
|
87
|
+
compileGlobRegex,
|
|
88
|
+
fallbackIgnoredDirs,
|
|
89
|
+
fdIgnoreArgs,
|
|
90
|
+
normalizeGlobInput,
|
|
91
|
+
rgIgnoreArgs
|
|
92
|
+
} from "./chunk-IZZI3SKQ.js";
|
|
52
93
|
import {
|
|
53
94
|
OBSERVATION_POLICY_SLACK_BYTES,
|
|
54
95
|
OBSERVE_SELF_CAPS,
|
|
@@ -59,61 +100,51 @@ import {
|
|
|
59
100
|
observationBudgetExhausted,
|
|
60
101
|
releaseObservation,
|
|
61
102
|
reserveObservation,
|
|
62
|
-
toolResultContextText
|
|
103
|
+
toolResultContextText
|
|
104
|
+
} from "./chunk-ZKQ63XZ5.js";
|
|
105
|
+
import {
|
|
106
|
+
createSafetyPolicyEngine,
|
|
107
|
+
formatModelRejection
|
|
108
|
+
} from "./chunk-IC7JXLOM.js";
|
|
109
|
+
import {
|
|
63
110
|
truncateHead
|
|
64
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-GHXGMFQ5.js";
|
|
65
112
|
import {
|
|
66
113
|
GREP_MAX_LINE_LENGTH,
|
|
67
114
|
truncateLine
|
|
68
115
|
} from "./chunk-KECNXMDE.js";
|
|
69
116
|
import {
|
|
70
|
-
compileGlobRegex,
|
|
71
|
-
fallbackIgnoredDirs,
|
|
72
|
-
fdIgnoreArgs,
|
|
73
|
-
normalizeGlobInput,
|
|
74
117
|
resolveReadPath,
|
|
75
118
|
resolveToCwd,
|
|
76
|
-
rgIgnoreArgs,
|
|
77
119
|
toPosixPath
|
|
78
|
-
} from "./chunk-
|
|
79
|
-
import {
|
|
80
|
-
parseAgentLedgerBody
|
|
81
|
-
} from "./chunk-VQD7NH7Z.js";
|
|
82
|
-
import {
|
|
83
|
-
hashToolCall
|
|
84
|
-
} from "./chunk-MUXNDNMZ.js";
|
|
85
|
-
import {
|
|
86
|
-
formatModelRejection
|
|
87
|
-
} from "./chunk-RAUOKUZV.js";
|
|
88
|
-
import {
|
|
89
|
-
StringEnum,
|
|
90
|
-
engineStreamSimple
|
|
91
|
-
} from "./chunk-QLAGXTTV.js";
|
|
92
|
-
import {
|
|
93
|
-
byteLength,
|
|
94
|
-
truncateUtf8
|
|
95
|
-
} from "./chunk-MYI32N4R.js";
|
|
96
|
-
import {
|
|
97
|
-
BusChannels
|
|
98
|
-
} from "./chunk-W5RM7YAH.js";
|
|
120
|
+
} from "./chunk-KP5BPXR3.js";
|
|
99
121
|
import {
|
|
100
122
|
extensionContentDigestWithCapture
|
|
101
123
|
} from "./chunk-XW2UZICE.js";
|
|
102
124
|
import {
|
|
103
125
|
classify
|
|
104
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-H2WSCZZT.js";
|
|
105
127
|
import {
|
|
106
128
|
protectArtifact,
|
|
107
129
|
protectedArtifactMutationBlockReason
|
|
108
|
-
} from "./chunk-
|
|
130
|
+
} from "./chunk-SQBT46OF.js";
|
|
131
|
+
import {
|
|
132
|
+
gitTool
|
|
133
|
+
} from "./chunk-YQYINEJI.js";
|
|
134
|
+
import {
|
|
135
|
+
byteLength,
|
|
136
|
+
truncateUtf8
|
|
137
|
+
} from "./chunk-MYI32N4R.js";
|
|
109
138
|
import {
|
|
110
139
|
CLIO_ARTIFACT_DIR,
|
|
111
140
|
artifactDefaultPath
|
|
112
141
|
} from "./chunk-NTTS3O53.js";
|
|
113
142
|
import {
|
|
114
143
|
ToolNames,
|
|
115
|
-
isBuiltinToolName
|
|
116
|
-
|
|
144
|
+
isBuiltinToolName,
|
|
145
|
+
isMcpToolName,
|
|
146
|
+
mcpToolName
|
|
147
|
+
} from "./chunk-V4XJWDHR.js";
|
|
117
148
|
import {
|
|
118
149
|
GUARDRAIL_DEFAULTS,
|
|
119
150
|
resolveGuardrail,
|
|
@@ -126,16 +157,21 @@ import {
|
|
|
126
157
|
require_dist
|
|
127
158
|
} from "./chunk-B5GGDIHT.js";
|
|
128
159
|
import {
|
|
129
|
-
|
|
130
|
-
|
|
160
|
+
StringEnum,
|
|
161
|
+
engineStreamSimple,
|
|
162
|
+
validateEngineToolArguments
|
|
163
|
+
} from "./chunk-UIU7MGZ3.js";
|
|
164
|
+
import {
|
|
165
|
+
parseAgentLedgerBody
|
|
166
|
+
} from "./chunk-VQD7NH7Z.js";
|
|
131
167
|
import {
|
|
132
168
|
buildSafeToolEnv,
|
|
133
169
|
runCommandVector
|
|
134
|
-
} from "./chunk-
|
|
170
|
+
} from "./chunk-XTQ7MEJG.js";
|
|
135
171
|
import {
|
|
136
172
|
decisionRef,
|
|
137
173
|
skillActivationFromToolDetails
|
|
138
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-NBPA5QM6.js";
|
|
139
175
|
import {
|
|
140
176
|
assertSafeId
|
|
141
177
|
} from "./chunk-UHW5V7HC.js";
|
|
@@ -652,6 +688,7 @@ function createLoopGuardRegistration(options) {
|
|
|
652
688
|
return true;
|
|
653
689
|
},
|
|
654
690
|
evaluate(input) {
|
|
691
|
+
if (input.metadata?.nested === true) return [];
|
|
655
692
|
if (input.hook === "after_tool") {
|
|
656
693
|
recordSuccessfulResult(input);
|
|
657
694
|
recordResultForStagnation(input);
|
|
@@ -1040,7 +1077,7 @@ function resolveAgentTools(input) {
|
|
|
1040
1077
|
const specs = [];
|
|
1041
1078
|
for (const name of effectiveToolNames(input)) {
|
|
1042
1079
|
const spec = input.registry.get(name);
|
|
1043
|
-
if (spec) specs.push(spec);
|
|
1080
|
+
if (spec && toolSpecPlacement(spec) === "direct") specs.push(spec);
|
|
1044
1081
|
}
|
|
1045
1082
|
specs.sort((a, b) => a.name.localeCompare(b.name));
|
|
1046
1083
|
return specs.map((spec) => toAgentTool(spec, input.registry, input.telemetry, input.invokeOptions));
|
|
@@ -1050,7 +1087,9 @@ function effectiveToolNames(input) {
|
|
|
1050
1087
|
...input.agentId !== void 0 ? { agentId: input.agentId } : {},
|
|
1051
1088
|
...input.task !== void 0 ? { task: input.task } : {}
|
|
1052
1089
|
};
|
|
1053
|
-
const
|
|
1090
|
+
const gatewayNames = input.registry.listGateway().map((spec) => spec.name);
|
|
1091
|
+
const registered = [...input.registry.listRegistered(), ...gatewayNames];
|
|
1092
|
+
const toolIds = applyToolProfile(registered, input.toolProfile, profileContext);
|
|
1054
1093
|
const allowed = input.allowedTools ? new Set(input.allowedTools) : null;
|
|
1055
1094
|
const includeInteractiveTools = input.includeInteractiveTools !== false;
|
|
1056
1095
|
const names = [];
|
|
@@ -1059,7 +1098,8 @@ function effectiveToolNames(input) {
|
|
|
1059
1098
|
if (allowed && !allowed.has(name)) continue;
|
|
1060
1099
|
names.push(name);
|
|
1061
1100
|
}
|
|
1062
|
-
return names;
|
|
1101
|
+
if (input.registry.get(ToolNames.Gateway) === void 0) return names;
|
|
1102
|
+
return withGatewayForCapabilities(names);
|
|
1063
1103
|
}
|
|
1064
1104
|
function resolveSessionTools(runtime, toolRegistry, invokeOptions, telemetry) {
|
|
1065
1105
|
if (!toolRegistry || runtime.runtimeResolution.capabilityDecisions.tools !== true) return [];
|
|
@@ -1258,6 +1298,558 @@ function patchWorkerRequestPayload(payload, model, options) {
|
|
|
1258
1298
|
return changed ? patched : void 0;
|
|
1259
1299
|
}
|
|
1260
1300
|
|
|
1301
|
+
// src/tools/gateway/mcp-capabilities.ts
|
|
1302
|
+
init_esm_shims();
|
|
1303
|
+
var MCP_RESULT_CONTEXT_BYTES = 16 * 1024;
|
|
1304
|
+
function mcpTrustRemedy(id) {
|
|
1305
|
+
return { remedy: `clio-coder mcp trust ${id}`, interactiveRemedy: `/mcp trust ${id}` };
|
|
1306
|
+
}
|
|
1307
|
+
function quoted(value) {
|
|
1308
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
1309
|
+
}
|
|
1310
|
+
function errorMessage2(error) {
|
|
1311
|
+
if (error instanceof McpError) return `${error.message} (${error.code})`;
|
|
1312
|
+
return error instanceof Error ? error.message : String(error);
|
|
1313
|
+
}
|
|
1314
|
+
function imageBlocks(result) {
|
|
1315
|
+
const images = [];
|
|
1316
|
+
for (const block of result.content) {
|
|
1317
|
+
if (block.type !== "image") continue;
|
|
1318
|
+
const { data, mimeType } = block;
|
|
1319
|
+
if (typeof data === "string" && typeof mimeType === "string" && mimeType.startsWith("image/")) {
|
|
1320
|
+
images.push({ type: "image", data, mimeType });
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
return images;
|
|
1324
|
+
}
|
|
1325
|
+
function createMcpCapabilitySource(options) {
|
|
1326
|
+
const registry = options.registry;
|
|
1327
|
+
const clientFactory = options.clientFactory ?? createMcpStdioClient;
|
|
1328
|
+
let states = null;
|
|
1329
|
+
let diagnostics = [];
|
|
1330
|
+
let exitHookInstalled = false;
|
|
1331
|
+
let closed = false;
|
|
1332
|
+
let closePromise = null;
|
|
1333
|
+
const teardowns = [];
|
|
1334
|
+
const killLaunchedOnExit = () => {
|
|
1335
|
+
for (const state of states?.values() ?? []) state.client?.killOwnedOnExit();
|
|
1336
|
+
};
|
|
1337
|
+
const installExitHook = () => {
|
|
1338
|
+
if (exitHookInstalled) return;
|
|
1339
|
+
exitHookInstalled = true;
|
|
1340
|
+
process.once("exit", killLaunchedOnExit);
|
|
1341
|
+
};
|
|
1342
|
+
const closeClient = (state) => {
|
|
1343
|
+
if (state.closing !== null) return state.closing;
|
|
1344
|
+
const client = state.client;
|
|
1345
|
+
if (client === null) return void 0;
|
|
1346
|
+
state.closing = client.close().then((outcome) => {
|
|
1347
|
+
teardowns.push({ id: state.declaration.id, outcome });
|
|
1348
|
+
state.client = null;
|
|
1349
|
+
if (!outcome.complete) {
|
|
1350
|
+
process.stderr.write(
|
|
1351
|
+
`[gateway] mcp server ${state.declaration.id}: process group ${outcome.pgid} survived SIGKILL for ${outcome.boundMs}ms; recorded, not signalled again
|
|
1352
|
+
`
|
|
1353
|
+
);
|
|
1354
|
+
}
|
|
1355
|
+
return outcome;
|
|
1356
|
+
});
|
|
1357
|
+
return state.closing;
|
|
1358
|
+
};
|
|
1359
|
+
const resolveStates = () => {
|
|
1360
|
+
if (states !== null) return states;
|
|
1361
|
+
const resolved = resolveMcpServers({
|
|
1362
|
+
cwd: options.cwd,
|
|
1363
|
+
...options.configDir ? { configDir: options.configDir } : {}
|
|
1364
|
+
});
|
|
1365
|
+
diagnostics = [
|
|
1366
|
+
...resolved.diagnostics.map((entry) => `${entry.scope} ${entry.path}: ${entry.message}`),
|
|
1367
|
+
...resolved.trustDiagnostics
|
|
1368
|
+
];
|
|
1369
|
+
states = new Map(
|
|
1370
|
+
resolved.servers.map((declaration) => [
|
|
1371
|
+
declaration.id,
|
|
1372
|
+
{
|
|
1373
|
+
declaration,
|
|
1374
|
+
client: null,
|
|
1375
|
+
connecting: null,
|
|
1376
|
+
closing: null,
|
|
1377
|
+
tools: [],
|
|
1378
|
+
truncated: false,
|
|
1379
|
+
registered: [],
|
|
1380
|
+
unregistrable: [],
|
|
1381
|
+
failure: null
|
|
1382
|
+
}
|
|
1383
|
+
])
|
|
1384
|
+
);
|
|
1385
|
+
return states;
|
|
1386
|
+
};
|
|
1387
|
+
const makeSpec = (state, tool, name) => {
|
|
1388
|
+
const { declaration } = state;
|
|
1389
|
+
const trustClass = declaration.trust.actionClass;
|
|
1390
|
+
const timeoutMs = declaration.timeoutMs ?? options.requestTimeoutMs;
|
|
1391
|
+
const spec = {
|
|
1392
|
+
name,
|
|
1393
|
+
description: `${tool.description.trim().length > 0 ? tool.description.trim() : `MCP tool ${tool.name}`}
|
|
1394
|
+
Local MCP server ${declaration.id} (${declaration.scope} scope), trusted with action class ${trustClass}; launching it does not sandbox it.`,
|
|
1395
|
+
parameters: tool.inputSchema,
|
|
1396
|
+
baseActionClass: trustClass,
|
|
1397
|
+
executionMode: "sequential",
|
|
1398
|
+
placement: "gateway",
|
|
1399
|
+
sourceInfo: { path: declaration.path, scope: "domain" },
|
|
1400
|
+
metadata: {
|
|
1401
|
+
objective: tool.description.trim().length > 0 ? tool.description.trim() : `MCP tool ${tool.name}`,
|
|
1402
|
+
uiLabel: `${declaration.id}/${tool.name}`,
|
|
1403
|
+
retrySafety: "unknown",
|
|
1404
|
+
// The session cap alone (64 KiB) let one search result spend a sixth
|
|
1405
|
+
// of a 131k window. Bound MCP output like the built-in observation
|
|
1406
|
+
// tools; the full text is offloaded and stays readable by path.
|
|
1407
|
+
resultSizePolicy: {
|
|
1408
|
+
kind: "bounded",
|
|
1409
|
+
maxBytes: MCP_RESULT_CONTEXT_BYTES,
|
|
1410
|
+
followUpHint: "Call again with a narrower query or the server's own limit/page arguments, or read the offloaded file in windows."
|
|
1411
|
+
},
|
|
1412
|
+
costLatency: "local_slow"
|
|
1413
|
+
},
|
|
1414
|
+
async run(args, invokeOptions) {
|
|
1415
|
+
const client = state.client;
|
|
1416
|
+
if (client === null || client.state().status !== "ready") {
|
|
1417
|
+
return {
|
|
1418
|
+
kind: "error",
|
|
1419
|
+
message: `${name}: mcp server ${declaration.id} is not connected${state.failure ? ` (${state.failure})` : ""}; a server that exited stays closed for this session`
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
try {
|
|
1423
|
+
const result = await client.callTool(tool.name, args, {
|
|
1424
|
+
...invokeOptions?.signal ? { signal: invokeOptions.signal } : {},
|
|
1425
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
1426
|
+
});
|
|
1427
|
+
const details = {
|
|
1428
|
+
server: declaration.id,
|
|
1429
|
+
tool: tool.name,
|
|
1430
|
+
contentTypes: result.content.map((block) => block.type),
|
|
1431
|
+
textTruncated: result.textTruncated,
|
|
1432
|
+
...result.structuredContent !== void 0 ? { structuredContent: result.structuredContent } : {},
|
|
1433
|
+
...result.structuredContentJson !== void 0 ? { structuredContentJson: result.structuredContentJson } : {}
|
|
1434
|
+
};
|
|
1435
|
+
if (result.isError) return { kind: "error", message: `${name}: ${result.text || "tool error"}`, details };
|
|
1436
|
+
const images = imageBlocks(result);
|
|
1437
|
+
return { kind: "ok", output: result.text, details, ...images.length > 0 ? { images } : {} };
|
|
1438
|
+
} catch (error) {
|
|
1439
|
+
if (error instanceof McpError && (error.code === "closed" || error.code === "spawn")) {
|
|
1440
|
+
state.failure = errorMessage2(error);
|
|
1441
|
+
}
|
|
1442
|
+
return { kind: "error", message: `${name}: ${errorMessage2(error)}` };
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1446
|
+
if (trustClass === "execute") {
|
|
1447
|
+
spec.safetyCall = () => ({
|
|
1448
|
+
tool: "bash",
|
|
1449
|
+
args: { command: [declaration.command, ...declaration.args].map(quoted).join(" ") }
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
return spec;
|
|
1453
|
+
};
|
|
1454
|
+
const connect = async (state) => {
|
|
1455
|
+
if (state.connecting !== null) return state.connecting;
|
|
1456
|
+
if (closed || state.client !== null || state.failure !== null) return;
|
|
1457
|
+
if (state.declaration.trust.status !== "trusted") return;
|
|
1458
|
+
state.connecting = (async () => {
|
|
1459
|
+
const { declaration } = state;
|
|
1460
|
+
let client = null;
|
|
1461
|
+
try {
|
|
1462
|
+
client = clientFactory(
|
|
1463
|
+
{
|
|
1464
|
+
id: declaration.id,
|
|
1465
|
+
command: declaration.command,
|
|
1466
|
+
args: declaration.args,
|
|
1467
|
+
cwd: declaration.cwd,
|
|
1468
|
+
env: declaration.env
|
|
1469
|
+
},
|
|
1470
|
+
{
|
|
1471
|
+
workspaceRoot: declaration.cwdRoot,
|
|
1472
|
+
...declaration.timeoutMs !== null ? { requestTimeoutMs: declaration.timeoutMs } : options.requestTimeoutMs !== void 0 ? { requestTimeoutMs: options.requestTimeoutMs } : {}
|
|
1473
|
+
}
|
|
1474
|
+
);
|
|
1475
|
+
state.client = client;
|
|
1476
|
+
installExitHook();
|
|
1477
|
+
await client.initialize();
|
|
1478
|
+
const listing = await client.listTools();
|
|
1479
|
+
state.tools = listing.tools;
|
|
1480
|
+
state.truncated = listing.truncated;
|
|
1481
|
+
for (const tool of listing.tools) {
|
|
1482
|
+
const name = mcpToolName(declaration.id, tool.name);
|
|
1483
|
+
if (name === null || ownerOf(name) !== state || registry.get(name) !== void 0) {
|
|
1484
|
+
state.unregistrable.push(tool.name);
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
registry.register(makeSpec(state, tool, name));
|
|
1488
|
+
state.registered.push(name);
|
|
1489
|
+
}
|
|
1490
|
+
} catch (error) {
|
|
1491
|
+
state.failure = errorMessage2(error);
|
|
1492
|
+
await closeClient(state);
|
|
1493
|
+
} finally {
|
|
1494
|
+
state.connecting = null;
|
|
1495
|
+
}
|
|
1496
|
+
})();
|
|
1497
|
+
return state.connecting;
|
|
1498
|
+
};
|
|
1499
|
+
const discover = async (state, signal) => {
|
|
1500
|
+
const aborted = () => new McpError("aborted", "MCP discovery aborted");
|
|
1501
|
+
if (signal?.aborted) throw aborted();
|
|
1502
|
+
let cleanup;
|
|
1503
|
+
const onAbort = () => {
|
|
1504
|
+
state.failure = errorMessage2(aborted());
|
|
1505
|
+
cleanup = closeClient(state);
|
|
1506
|
+
};
|
|
1507
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1508
|
+
try {
|
|
1509
|
+
await connect(state);
|
|
1510
|
+
await cleanup;
|
|
1511
|
+
if (signal?.aborted) throw aborted();
|
|
1512
|
+
} finally {
|
|
1513
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
const listingFor = (state) => {
|
|
1517
|
+
const { declaration } = state;
|
|
1518
|
+
const base = { id: declaration.id, scope: declaration.scope, actionClass: declaration.trust.actionClass };
|
|
1519
|
+
if (declaration.trust.status !== "trusted") {
|
|
1520
|
+
return {
|
|
1521
|
+
...base,
|
|
1522
|
+
status: declaration.trust.status,
|
|
1523
|
+
reason: declaration.trust.reason,
|
|
1524
|
+
...mcpTrustRemedy(declaration.id)
|
|
1525
|
+
};
|
|
1526
|
+
}
|
|
1527
|
+
if (state.failure !== null) {
|
|
1528
|
+
return { ...base, status: "failed", reason: state.failure };
|
|
1529
|
+
}
|
|
1530
|
+
if (state.client !== null) {
|
|
1531
|
+
return {
|
|
1532
|
+
...base,
|
|
1533
|
+
status: "connected",
|
|
1534
|
+
tools: [...state.registered],
|
|
1535
|
+
...state.truncated ? { truncated: true } : {},
|
|
1536
|
+
...state.unregistrable.length > 0 ? { unregistrable: [...state.unregistrable] } : {}
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
return { ...base, status: "trusted" };
|
|
1540
|
+
};
|
|
1541
|
+
const ownerOf = (name) => {
|
|
1542
|
+
let owner = null;
|
|
1543
|
+
for (const state of resolveStates().values()) {
|
|
1544
|
+
if (name.startsWith(`mcp_${state.declaration.id}__`) && (owner === null || state.declaration.id.length > owner.declaration.id.length)) {
|
|
1545
|
+
owner = state;
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
return owner;
|
|
1549
|
+
};
|
|
1550
|
+
return {
|
|
1551
|
+
async list(invokeOptions) {
|
|
1552
|
+
if (invokeOptions?.signal?.aborted) throw new McpError("aborted", "MCP discovery aborted");
|
|
1553
|
+
const all = [...resolveStates().values()];
|
|
1554
|
+
const results = await Promise.allSettled(all.map((state) => discover(state, invokeOptions?.signal)));
|
|
1555
|
+
for (const result of results) {
|
|
1556
|
+
if (result.status === "rejected") throw result.reason;
|
|
1557
|
+
}
|
|
1558
|
+
return { servers: all.map(listingFor), diagnostics: [...diagnostics] };
|
|
1559
|
+
},
|
|
1560
|
+
async ensure(name, invokeOptions) {
|
|
1561
|
+
if (invokeOptions?.signal?.aborted) throw new McpError("aborted", "MCP discovery aborted");
|
|
1562
|
+
const owner = ownerOf(name);
|
|
1563
|
+
if (owner === null) return { spec: null, reason: `no declared MCP server owns ${name}` };
|
|
1564
|
+
const trust = owner.declaration.trust;
|
|
1565
|
+
if (trust.status !== "trusted") {
|
|
1566
|
+
const remedy = mcpTrustRemedy(owner.declaration.id);
|
|
1567
|
+
return {
|
|
1568
|
+
spec: null,
|
|
1569
|
+
reason: `mcp server ${owner.declaration.id} is ${trust.status} (${trust.reason}); it is never launched until trusted: run ${remedy.remedy} (${remedy.interactiveRemedy} in an interactive session)`
|
|
1570
|
+
};
|
|
1571
|
+
}
|
|
1572
|
+
await discover(owner, invokeOptions?.signal);
|
|
1573
|
+
const spec = registry.get(name);
|
|
1574
|
+
if (spec !== void 0 && owner.registered.includes(spec.name)) return { spec };
|
|
1575
|
+
return {
|
|
1576
|
+
spec: null,
|
|
1577
|
+
reason: owner.failure !== null ? `mcp server ${owner.declaration.id} failed: ${owner.failure}` : `mcp server ${owner.declaration.id} offers no tool named ${name.slice(`mcp_${owner.declaration.id}__`.length)}`
|
|
1578
|
+
};
|
|
1579
|
+
},
|
|
1580
|
+
authorityNote(name) {
|
|
1581
|
+
const owner = ownerOf(name);
|
|
1582
|
+
if (owner === null) return null;
|
|
1583
|
+
const { declaration } = owner;
|
|
1584
|
+
return `Local stdio MCP server ${declaration.id} (${declaration.scope} scope, declared in ${declaration.path}), trusted with action class ${declaration.trust.actionClass}: ${declaration.trust.actionClass === "unknown" ? "every call asks for approval and read-only denies it" : declaration.trust.actionClass === "execute" ? "calls are admitted like an unrecognized shell command" : "calls run as reads at every autonomy level"}. Launching the server does not sandbox it.`;
|
|
1585
|
+
},
|
|
1586
|
+
connectedIds() {
|
|
1587
|
+
return [...states?.values() ?? []].filter((state) => state.client !== null).map((state) => state.declaration.id);
|
|
1588
|
+
},
|
|
1589
|
+
teardownReports() {
|
|
1590
|
+
return [...teardowns];
|
|
1591
|
+
},
|
|
1592
|
+
close() {
|
|
1593
|
+
if (closePromise !== null) return closePromise;
|
|
1594
|
+
closed = true;
|
|
1595
|
+
closePromise = (async () => {
|
|
1596
|
+
const all = [...states?.values() ?? []];
|
|
1597
|
+
await Promise.all(all.map(closeClient));
|
|
1598
|
+
await Promise.all(all.map((state) => state.connecting));
|
|
1599
|
+
const report = { incomplete: [] };
|
|
1600
|
+
for (const { id, outcome } of teardowns) {
|
|
1601
|
+
if (!outcome.complete) report.incomplete.push({ id, pgid: outcome.pgid, boundMs: outcome.boundMs });
|
|
1602
|
+
}
|
|
1603
|
+
if (exitHookInstalled) {
|
|
1604
|
+
process.removeListener("exit", killLaunchedOnExit);
|
|
1605
|
+
exitHookInstalled = false;
|
|
1606
|
+
}
|
|
1607
|
+
return report;
|
|
1608
|
+
})();
|
|
1609
|
+
return closePromise;
|
|
1610
|
+
}
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
// src/tools/gateway/index.ts
|
|
1615
|
+
init_esm_shims();
|
|
1616
|
+
var GATEWAY_OPS = ["find", "describe", "call"];
|
|
1617
|
+
var GATEWAY_FIND_MAX_ENTRIES = 300;
|
|
1618
|
+
var DESCRIPTION = `Reach secondary capabilities on demand. op="find" lists them as JSON {name, kind: builtin|extension|mcp, description, actionClass} (query filters by name or description); op="describe" returns one capability's full description, JSON parameter schema, and authority notes; op="call" runs one with args under the same admission as a direct tool: its own action class, approval, and evidence apply and the result is the capability's result. Capabilities: artifact (terminal plan/review/report documents), web_read (GET-only web reading), web_fetch (full HTTP requests), git (read-only status/diff/log), evidence, credential_present, clio_docs, clio_library, data (CSV/TSV, JSON, JSONL inspection), installed extension commands, and trusted local MCP servers.`;
|
|
1619
|
+
var gatewayToolSurface = {
|
|
1620
|
+
name: ToolNames.Gateway,
|
|
1621
|
+
description: DESCRIPTION,
|
|
1622
|
+
parameters: typebox_exports.Object({
|
|
1623
|
+
op: StringEnum(GATEWAY_OPS, { description: "find, describe, or call." }),
|
|
1624
|
+
capability: typebox_exports.Optional(typebox_exports.String({ description: "describe and call: the capability name from find." })),
|
|
1625
|
+
query: typebox_exports.Optional(typebox_exports.String({ description: "find: case-insensitive filter over names and descriptions." })),
|
|
1626
|
+
args: typebox_exports.Optional(
|
|
1627
|
+
typebox_exports.Record(typebox_exports.String(), typebox_exports.Unknown(), {
|
|
1628
|
+
description: "call: the capability's arguments, matching its describe schema."
|
|
1629
|
+
})
|
|
1630
|
+
)
|
|
1631
|
+
}),
|
|
1632
|
+
baseActionClass: "read",
|
|
1633
|
+
executionMode: "sequential"
|
|
1634
|
+
};
|
|
1635
|
+
function isRecord3(value) {
|
|
1636
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1637
|
+
}
|
|
1638
|
+
function prepareGatewayArguments(args) {
|
|
1639
|
+
const out = { ...args };
|
|
1640
|
+
if (typeof out.capability !== "string") {
|
|
1641
|
+
const alias = out.name ?? out.tool;
|
|
1642
|
+
if (typeof alias === "string") out.capability = alias;
|
|
1643
|
+
}
|
|
1644
|
+
if (typeof out.args === "string") {
|
|
1645
|
+
try {
|
|
1646
|
+
const parsed = JSON.parse(out.args);
|
|
1647
|
+
if (isRecord3(parsed)) out.args = parsed;
|
|
1648
|
+
} catch {
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
if (typeof out.op !== "string") {
|
|
1652
|
+
if (typeof out.capability === "string" && out.args !== void 0) out.op = "call";
|
|
1653
|
+
else if (typeof out.capability === "string") out.op = "describe";
|
|
1654
|
+
else out.op = "find";
|
|
1655
|
+
}
|
|
1656
|
+
return out;
|
|
1657
|
+
}
|
|
1658
|
+
function firstSentence(text) {
|
|
1659
|
+
const line = text.split("\n")[0]?.trim() ?? "";
|
|
1660
|
+
const match = /^(.*?[.!?])(?:\s|$)/u.exec(line);
|
|
1661
|
+
return (match?.[1] ?? line).slice(0, 240);
|
|
1662
|
+
}
|
|
1663
|
+
function autonomyNote(actionClass) {
|
|
1664
|
+
switch (actionClass) {
|
|
1665
|
+
case "read":
|
|
1666
|
+
return "Read class: runs at every autonomy level.";
|
|
1667
|
+
case "write":
|
|
1668
|
+
return "Write class: parks for operator approval at suggest, runs at auto-edit and full-auto, and is denied at read-only.";
|
|
1669
|
+
case "execute":
|
|
1670
|
+
return "Execute class: an unrecognized command asks at auto-edit, runs at full-auto, and is denied at read-only.";
|
|
1671
|
+
case "dispatch":
|
|
1672
|
+
return "Dispatch class: plan-scale calls ask below full-auto; denied at read-only.";
|
|
1673
|
+
case "unknown":
|
|
1674
|
+
return "No action class was declared: every call asks for approval and read-only denies it.";
|
|
1675
|
+
default:
|
|
1676
|
+
return `Action class ${actionClass}.`;
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
function createGatewayTool(deps) {
|
|
1680
|
+
const { registry } = deps;
|
|
1681
|
+
const allowedSet = (options) => options?.allowedTools ? new Set(options.allowedTools) : null;
|
|
1682
|
+
const resolveCapability = async (name, options) => {
|
|
1683
|
+
let spec = registry.get(name);
|
|
1684
|
+
if (spec === void 0 && isMcpToolName(name) && deps.mcp) {
|
|
1685
|
+
const ensured = await deps.mcp.ensure(name, options?.signal ? { signal: options.signal } : {});
|
|
1686
|
+
if (ensured.spec === null)
|
|
1687
|
+
return { spec: null, message: `gateway: ${ensured.reason ?? `unknown capability ${name}`}` };
|
|
1688
|
+
spec = ensured.spec;
|
|
1689
|
+
}
|
|
1690
|
+
if (spec === void 0) {
|
|
1691
|
+
return {
|
|
1692
|
+
spec: null,
|
|
1693
|
+
message: `gateway: unknown capability "${name}"; run gateway(op="find") to list the capabilities this session offers`
|
|
1694
|
+
};
|
|
1695
|
+
}
|
|
1696
|
+
if (toolSpecPlacement(spec) === "direct") {
|
|
1697
|
+
return {
|
|
1698
|
+
spec: null,
|
|
1699
|
+
message: `gateway: "${name}" is a direct tool with an attached schema; call it directly, not through the gateway`
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
return { spec };
|
|
1703
|
+
};
|
|
1704
|
+
const outsideSurface = (name, allowed) => ({
|
|
1705
|
+
kind: "error",
|
|
1706
|
+
message: `gateway: capability "${name}" is not on this run's admitted tool surface (${[...allowed].sort().join(", ")}); the recipe did not declare it, so the gateway refuses to call it`
|
|
1707
|
+
});
|
|
1708
|
+
const runFind = async (args, options) => {
|
|
1709
|
+
const query = typeof args.query === "string" ? args.query.trim().toLowerCase() : "";
|
|
1710
|
+
const allowed = allowedSet(options);
|
|
1711
|
+
const reservation = reserveObservation(GATEWAY_FIND_SELF_CAP_BYTES, options);
|
|
1712
|
+
if (reservation.exhausted) {
|
|
1713
|
+
return observationBudgetExhausted({
|
|
1714
|
+
tool: ToolNames.Gateway,
|
|
1715
|
+
unit: "entries",
|
|
1716
|
+
reservation,
|
|
1717
|
+
subject: query.length > 0 ? `find query=${query}` : "find",
|
|
1718
|
+
hint: "Continue in a follow-up turn."
|
|
1719
|
+
});
|
|
1720
|
+
}
|
|
1721
|
+
commitObservationReservation(reservation);
|
|
1722
|
+
try {
|
|
1723
|
+
let servers = [];
|
|
1724
|
+
let diagnostics = [];
|
|
1725
|
+
if (deps.mcp && allowed === null) {
|
|
1726
|
+
const listing = await deps.mcp.list(options?.signal ? { signal: options.signal } : {});
|
|
1727
|
+
servers = listing.servers;
|
|
1728
|
+
diagnostics = listing.diagnostics;
|
|
1729
|
+
}
|
|
1730
|
+
const entries = registry.listGateway().filter((spec) => allowed === null || allowed.has(spec.name)).map((spec) => ({
|
|
1731
|
+
name: spec.name,
|
|
1732
|
+
kind: gatewayCapabilityKind(spec.name),
|
|
1733
|
+
description: firstSentence(spec.description),
|
|
1734
|
+
actionClass: spec.baseActionClass
|
|
1735
|
+
})).filter(
|
|
1736
|
+
(entry) => query.length === 0 || entry.name.toLowerCase().includes(query) || entry.description.toLowerCase().includes(query)
|
|
1737
|
+
).sort((left, right) => left.name.localeCompare(right.name));
|
|
1738
|
+
const total = entries.length;
|
|
1739
|
+
const shown = entries.slice(0, GATEWAY_FIND_MAX_ENTRIES);
|
|
1740
|
+
const truncated = shown.length < total;
|
|
1741
|
+
const payload = {
|
|
1742
|
+
capabilities: shown,
|
|
1743
|
+
count: shown.length,
|
|
1744
|
+
total,
|
|
1745
|
+
...servers.length > 0 ? { servers } : {},
|
|
1746
|
+
...diagnostics.length > 0 ? { diagnostics } : {},
|
|
1747
|
+
...truncated ? { note: "listing truncated; narrow it with query" } : {}
|
|
1748
|
+
};
|
|
1749
|
+
return finalizeObservation({
|
|
1750
|
+
tool: ToolNames.Gateway,
|
|
1751
|
+
unit: "entries",
|
|
1752
|
+
format: "json",
|
|
1753
|
+
output: JSON.stringify(payload),
|
|
1754
|
+
shownCount: shown.length,
|
|
1755
|
+
totalCount: total,
|
|
1756
|
+
truncated,
|
|
1757
|
+
...truncated ? { next: "query=<narrower terms>" } : {},
|
|
1758
|
+
details: { op: "find", count: shown.length, total, servers: servers.length },
|
|
1759
|
+
reservation,
|
|
1760
|
+
...options ? { options } : {}
|
|
1761
|
+
});
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
releaseObservation(reservation);
|
|
1764
|
+
return { kind: "error", message: `gateway: find failed: ${error instanceof Error ? error.message : String(error)}` };
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
const runDescribe = async (args, options) => {
|
|
1768
|
+
const name = typeof args.capability === "string" ? args.capability.trim() : "";
|
|
1769
|
+
if (name.length === 0) return { kind: "error", message: 'gateway: op="describe" requires capability' };
|
|
1770
|
+
const allowed = allowedSet(options);
|
|
1771
|
+
if (allowed !== null && !allowed.has(name)) return outsideSurface(name, allowed);
|
|
1772
|
+
const resolved = await resolveCapability(name, options);
|
|
1773
|
+
if (resolved.spec === null) return { kind: "error", message: resolved.message };
|
|
1774
|
+
const spec = resolved.spec;
|
|
1775
|
+
const kind = gatewayCapabilityKind(spec.name);
|
|
1776
|
+
const authority = [
|
|
1777
|
+
`Runs through the same admission as a direct call, under its own name and action class (${spec.baseActionClass}); the approval overlay, audit row, and ledger record name ${spec.name}, not the gateway.`,
|
|
1778
|
+
autonomyNote(spec.baseActionClass)
|
|
1779
|
+
];
|
|
1780
|
+
if (spec.name === ToolNames.WebFetch) {
|
|
1781
|
+
authority.push(
|
|
1782
|
+
"A non-GET method or a body is an outward action and asks at suggest and auto-edit; use web_read when a plain GET is enough."
|
|
1783
|
+
);
|
|
1784
|
+
}
|
|
1785
|
+
if (spec.name === ToolNames.Artifact) {
|
|
1786
|
+
authority.push("Terminal: writing the artifact completes the turn, so close the task board before calling it.");
|
|
1787
|
+
}
|
|
1788
|
+
if (kind === "extension") {
|
|
1789
|
+
authority.push(
|
|
1790
|
+
`Harness extension${spec.sourceInfo?.extension ? ` ${spec.sourceInfo.extension.contentDigest.slice(0, 12)}` : ""}: an installed command run with JSON input on the workspace; its argv is classified like a bash command, and running it does not sandbox it.`
|
|
1791
|
+
);
|
|
1792
|
+
}
|
|
1793
|
+
const mcpNote = kind === "mcp" ? deps.mcp?.authorityNote(spec.name) : null;
|
|
1794
|
+
if (mcpNote) authority.push(mcpNote);
|
|
1795
|
+
const payload = {
|
|
1796
|
+
name: spec.name,
|
|
1797
|
+
kind,
|
|
1798
|
+
description: spec.description,
|
|
1799
|
+
parameters: wireParameterSchema(spec.parameters),
|
|
1800
|
+
actionClass: spec.baseActionClass,
|
|
1801
|
+
executionMode: spec.executionMode ?? "sequential",
|
|
1802
|
+
authority
|
|
1803
|
+
};
|
|
1804
|
+
return { kind: "ok", output: JSON.stringify(payload), details: { op: "describe", described: spec.name } };
|
|
1805
|
+
};
|
|
1806
|
+
const runCall = async (args, options) => {
|
|
1807
|
+
const name = typeof args.capability === "string" ? args.capability.trim() : "";
|
|
1808
|
+
if (name.length === 0) return { kind: "error", message: 'gateway: op="call" requires capability' };
|
|
1809
|
+
const allowed = allowedSet(options);
|
|
1810
|
+
if (allowed !== null && !allowed.has(name)) return outsideSurface(name, allowed);
|
|
1811
|
+
const resolved = await resolveCapability(name, options);
|
|
1812
|
+
if (resolved.spec === null) return { kind: "error", message: resolved.message };
|
|
1813
|
+
const spec = resolved.spec;
|
|
1814
|
+
if (args.args !== void 0 && !isRecord3(args.args)) {
|
|
1815
|
+
return { kind: "error", message: `gateway: args for ${spec.name} must be a JSON object` };
|
|
1816
|
+
}
|
|
1817
|
+
const rawArgs = isRecord3(args.args) ? args.args : {};
|
|
1818
|
+
let validated;
|
|
1819
|
+
try {
|
|
1820
|
+
validated = validateEngineToolArguments(
|
|
1821
|
+
{ name: spec.name, description: spec.description, parameters: spec.parameters },
|
|
1822
|
+
{ type: "toolCall", id: options?.toolCallId ?? "", name: spec.name, arguments: rawArgs }
|
|
1823
|
+
);
|
|
1824
|
+
} catch (error) {
|
|
1825
|
+
return {
|
|
1826
|
+
kind: "error",
|
|
1827
|
+
message: `gateway: ${spec.name} arguments rejected: ${error instanceof Error ? error.message : String(error)}. Use gateway(op="describe", capability="${spec.name}") for the schema.`
|
|
1828
|
+
};
|
|
1829
|
+
}
|
|
1830
|
+
const { approval: _approval, ...outer } = options ?? {};
|
|
1831
|
+
const verdict = await registry.invoke({ tool: spec.name, args: validated }, { ...outer, nested: true });
|
|
1832
|
+
if (verdict.kind === "not_visible") return { kind: "error", message: `gateway: ${verdict.reason}` };
|
|
1833
|
+
if (verdict.kind === "blocked") return nestedBlockedResult(verdict);
|
|
1834
|
+
return nestedExecutedResult(
|
|
1835
|
+
{ ...verdict.result, details: { ...verdict.result.details, capability: spec.name } },
|
|
1836
|
+
verdict.decision
|
|
1837
|
+
);
|
|
1838
|
+
};
|
|
1839
|
+
return {
|
|
1840
|
+
...gatewayToolSurface,
|
|
1841
|
+
prepareArguments: prepareGatewayArguments,
|
|
1842
|
+
async run(rawArgs, options) {
|
|
1843
|
+
const args = prepareGatewayArguments(rawArgs);
|
|
1844
|
+
const op = typeof args.op === "string" ? args.op : "";
|
|
1845
|
+
if (op === "find") return runFind(args, options);
|
|
1846
|
+
if (op === "describe") return runDescribe(args, options);
|
|
1847
|
+
if (op === "call") return runCall(args, options);
|
|
1848
|
+
return { kind: "error", message: `gateway: op must be find, describe, or call; got '${op}'` };
|
|
1849
|
+
}
|
|
1850
|
+
};
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1261
1853
|
// src/tools/lazy-tool.ts
|
|
1262
1854
|
init_esm_shims();
|
|
1263
1855
|
function surfaceSnapshot(spec) {
|
|
@@ -1311,20 +1903,29 @@ init_esm_shims();
|
|
|
1311
1903
|
|
|
1312
1904
|
// src/tools/artifact.ts
|
|
1313
1905
|
init_esm_shims();
|
|
1314
|
-
import { mkdirSync, writeFileSync } from "node:fs";
|
|
1315
1906
|
import path from "node:path";
|
|
1316
1907
|
|
|
1317
1908
|
// src/tools/file-mutation-queue.ts
|
|
1318
1909
|
init_esm_shims();
|
|
1319
|
-
import {
|
|
1320
|
-
import {
|
|
1910
|
+
import { randomUUID } from "node:crypto";
|
|
1911
|
+
import { lstatSync, readlinkSync, realpathSync } from "node:fs";
|
|
1912
|
+
import { lstat, mkdir, open, readlink, realpath, rename, stat, unlink } from "node:fs/promises";
|
|
1913
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
1321
1914
|
var fileMutationQueues = /* @__PURE__ */ new Map();
|
|
1322
|
-
function mutationQueueKey(filePath) {
|
|
1915
|
+
function mutationQueueKey(filePath, depth = 0) {
|
|
1323
1916
|
const resolved = resolve(filePath);
|
|
1917
|
+
if (depth > 40) throw new Error("Too many symbolic links");
|
|
1324
1918
|
try {
|
|
1325
1919
|
return realpathSync.native(resolved);
|
|
1326
1920
|
} catch {
|
|
1327
|
-
|
|
1921
|
+
try {
|
|
1922
|
+
if (lstatSync(resolved).isSymbolicLink()) {
|
|
1923
|
+
return mutationQueueKey(resolve(dirname(resolved), readlinkSync(resolved)), depth + 1);
|
|
1924
|
+
}
|
|
1925
|
+
} catch {
|
|
1926
|
+
}
|
|
1927
|
+
const parent = dirname(resolved);
|
|
1928
|
+
return parent === resolved ? resolved : join(mutationQueueKey(parent, depth), basename(resolved));
|
|
1328
1929
|
}
|
|
1329
1930
|
}
|
|
1330
1931
|
async function withFileMutationQueue(filePath, fn) {
|
|
@@ -1346,6 +1947,73 @@ async function withFileMutationQueue(filePath, fn) {
|
|
|
1346
1947
|
}
|
|
1347
1948
|
}
|
|
1348
1949
|
}
|
|
1950
|
+
async function resolvePublishTarget(filePath, depth = 0) {
|
|
1951
|
+
if (depth > 40) throw new Error("Too many symbolic links");
|
|
1952
|
+
const absolute = resolve(filePath);
|
|
1953
|
+
try {
|
|
1954
|
+
const info = await lstat(absolute);
|
|
1955
|
+
if (info.isSymbolicLink()) {
|
|
1956
|
+
return resolvePublishTarget(resolve(dirname(absolute), await readlink(absolute)), depth + 1);
|
|
1957
|
+
}
|
|
1958
|
+
if (!info.isFile()) throw new Error(`Refusing non-file target (including directories): ${filePath}`);
|
|
1959
|
+
} catch (error) {
|
|
1960
|
+
if (error.code !== "ENOENT") throw error;
|
|
1961
|
+
}
|
|
1962
|
+
await mkdir(dirname(absolute), { recursive: true });
|
|
1963
|
+
return join(await realpath(dirname(absolute)), basename(absolute));
|
|
1964
|
+
}
|
|
1965
|
+
async function publishFileAtomically(filePath, content, options = {}) {
|
|
1966
|
+
let tempPath;
|
|
1967
|
+
try {
|
|
1968
|
+
const target = await resolvePublishTarget(filePath);
|
|
1969
|
+
const previous = await stat(target).catch((error) => {
|
|
1970
|
+
if (error.code === "ENOENT") return null;
|
|
1971
|
+
throw error;
|
|
1972
|
+
});
|
|
1973
|
+
if (previous && !previous.isFile()) throw new Error(`Refusing directory or non-file target: ${filePath}`);
|
|
1974
|
+
tempPath = join(dirname(target), `.clio-coder-publish-${randomUUID()}.tmp`);
|
|
1975
|
+
const handle = await open(tempPath, "wx", previous ? previous.mode & 4095 : 438);
|
|
1976
|
+
let after;
|
|
1977
|
+
try {
|
|
1978
|
+
await handle.writeFile(content);
|
|
1979
|
+
if (previous) await handle.chmod(previous.mode & 4095);
|
|
1980
|
+
await handle.sync();
|
|
1981
|
+
const info = await handle.stat();
|
|
1982
|
+
after = { bytes: info.size, mtimeMs: info.mtimeMs };
|
|
1983
|
+
} finally {
|
|
1984
|
+
await handle.close();
|
|
1985
|
+
}
|
|
1986
|
+
await (options.rename ?? rename)(tempPath, target);
|
|
1987
|
+
tempPath = void 0;
|
|
1988
|
+
const result = {
|
|
1989
|
+
before: previous ? { bytes: previous.size, mtimeMs: previous.mtimeMs } : null,
|
|
1990
|
+
after
|
|
1991
|
+
};
|
|
1992
|
+
try {
|
|
1993
|
+
const directory = await open(dirname(target), "r");
|
|
1994
|
+
try {
|
|
1995
|
+
await directory.sync();
|
|
1996
|
+
} finally {
|
|
1997
|
+
await directory.close();
|
|
1998
|
+
}
|
|
1999
|
+
} catch (error) {
|
|
2000
|
+
result.durabilityWarning = `Published, but directory fsync was unavailable or failed: ${String(error)}`;
|
|
2001
|
+
}
|
|
2002
|
+
return result;
|
|
2003
|
+
} catch (error) {
|
|
2004
|
+
let cleanup = "";
|
|
2005
|
+
if (tempPath) {
|
|
2006
|
+
try {
|
|
2007
|
+
await unlink(tempPath);
|
|
2008
|
+
} catch (cleanupError) {
|
|
2009
|
+
if (cleanupError.code !== "ENOENT") {
|
|
2010
|
+
cleanup = ` Temporary file cleanup failed at ${tempPath}: ${String(cleanupError)}`;
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
throw new Error(`Nothing was published: ${String(error)}.${cleanup}`, { cause: error });
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
1349
2017
|
|
|
1350
2018
|
// src/tools/artifact.ts
|
|
1351
2019
|
var ARTIFACT_KINDS = ["plan", "review", "report"];
|
|
@@ -1368,11 +2036,9 @@ async function writeTerminalArtifact(kind, args, cwd) {
|
|
|
1368
2036
|
const body = title.length > 0 && !content.trimStart().startsWith("#") ? `# ${title}
|
|
1369
2037
|
|
|
1370
2038
|
${content}` : content;
|
|
2039
|
+
let published;
|
|
1371
2040
|
try {
|
|
1372
|
-
await withFileMutationQueue(target,
|
|
1373
|
-
mkdirSync(path.dirname(target), { recursive: true });
|
|
1374
|
-
writeFileSync(target, body, "utf8");
|
|
1375
|
-
});
|
|
2041
|
+
published = await withFileMutationQueue(target, () => publishFileAtomically(target, body));
|
|
1376
2042
|
} catch (err) {
|
|
1377
2043
|
return { kind: "error", message: `artifact: ${err instanceof Error ? err.message : String(err)}` };
|
|
1378
2044
|
}
|
|
@@ -1380,10 +2046,16 @@ ${content}` : content;
|
|
|
1380
2046
|
const bytes = Buffer.byteLength(body, "utf8");
|
|
1381
2047
|
return {
|
|
1382
2048
|
kind: "ok",
|
|
1383
|
-
output: `wrote ${kind} artifact (${bytes}B) to ${rel}
|
|
2049
|
+
output: `wrote ${kind} artifact (${bytes}B) to ${rel}${published.durabilityWarning ? `
|
|
2050
|
+
${published.durabilityWarning}` : ""}`,
|
|
1384
2051
|
// shownBytes is the artifact's real size; the ledger otherwise measures
|
|
1385
2052
|
// this confirmation sentence (a 4753B plan rendered as "60B", #76).
|
|
1386
|
-
details: {
|
|
2053
|
+
details: {
|
|
2054
|
+
kind,
|
|
2055
|
+
paths: [target],
|
|
2056
|
+
observation: { shownBytes: bytes },
|
|
2057
|
+
file: { before: published.before, after: published.after }
|
|
2058
|
+
},
|
|
1387
2059
|
// Writing the artifact is the whole turn; terminate skips the follow-up
|
|
1388
2060
|
// LLM call that would only restate what was just written.
|
|
1389
2061
|
terminate: true
|
|
@@ -1641,7 +2313,8 @@ function createDecideTool(deps = {}) {
|
|
|
1641
2313
|
|
|
1642
2314
|
// src/tools/edit.ts
|
|
1643
2315
|
init_esm_shims();
|
|
1644
|
-
import {
|
|
2316
|
+
import { readFile, stat as stat2 } from "node:fs/promises";
|
|
2317
|
+
import { setImmediate as yieldImmediate } from "node:timers/promises";
|
|
1645
2318
|
|
|
1646
2319
|
// src/tools/edit-diff.ts
|
|
1647
2320
|
init_esm_shims();
|
|
@@ -2183,12 +2856,6 @@ function capDiffLine(text) {
|
|
|
2183
2856
|
if (text.length <= MAX_DIFF_LINE_CHARS) return text;
|
|
2184
2857
|
return `${text.slice(0, MAX_DIFF_LINE_CHARS)}\u2026 (+${text.length - MAX_DIFF_LINE_CHARS} chars)`;
|
|
2185
2858
|
}
|
|
2186
|
-
function detectLineEnding(content) {
|
|
2187
|
-
const crlfIdx = content.indexOf("\r\n");
|
|
2188
|
-
const lfIdx = content.indexOf("\n");
|
|
2189
|
-
if (lfIdx === -1 || crlfIdx === -1) return "\n";
|
|
2190
|
-
return crlfIdx < lfIdx ? "\r\n" : "\n";
|
|
2191
|
-
}
|
|
2192
2859
|
function normalizeToLF(text) {
|
|
2193
2860
|
return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
2194
2861
|
}
|
|
@@ -2580,6 +3247,78 @@ function generateDiffString(oldContent, newContent, contextLines = 4) {
|
|
|
2580
3247
|
}
|
|
2581
3248
|
|
|
2582
3249
|
// src/tools/edit.ts
|
|
3250
|
+
var DIFF_LIMIT = 1024 * 1024;
|
|
3251
|
+
var VALIDATION_CHUNK = 64 * 1024;
|
|
3252
|
+
async function invalidUtf8Offset(bytes) {
|
|
3253
|
+
const decoder = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
3254
|
+
let failingStart = 0;
|
|
3255
|
+
for (let start2 = 0; start2 < bytes.length; start2 += VALIDATION_CHUNK) {
|
|
3256
|
+
try {
|
|
3257
|
+
decoder.decode(bytes.subarray(start2, start2 + VALIDATION_CHUNK), { stream: true });
|
|
3258
|
+
} catch {
|
|
3259
|
+
failingStart = start2;
|
|
3260
|
+
break;
|
|
3261
|
+
}
|
|
3262
|
+
failingStart = Math.min(start2 + VALIDATION_CHUNK, bytes.length);
|
|
3263
|
+
await yieldImmediate();
|
|
3264
|
+
}
|
|
3265
|
+
let start = Math.max(0, failingStart - 4);
|
|
3266
|
+
while (start > 0 && ((bytes[start] ?? 0) & 192) === 128) start -= 1;
|
|
3267
|
+
const narrow = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
3268
|
+
let sequenceStart = start;
|
|
3269
|
+
const end = Math.min(bytes.length, failingStart + VALIDATION_CHUNK);
|
|
3270
|
+
for (let i = start; i < end; i += 1) {
|
|
3271
|
+
try {
|
|
3272
|
+
if (narrow.decode(bytes.subarray(i, i + 1), { stream: true }).length > 0) sequenceStart = i + 1;
|
|
3273
|
+
} catch {
|
|
3274
|
+
return sequenceStart;
|
|
3275
|
+
}
|
|
3276
|
+
if ((i - start + 1) % 1024 === 0) await yieldImmediate();
|
|
3277
|
+
}
|
|
3278
|
+
return sequenceStart;
|
|
3279
|
+
}
|
|
3280
|
+
async function classifyEndings(bytes) {
|
|
3281
|
+
let crlf = false;
|
|
3282
|
+
let lf = false;
|
|
3283
|
+
let nextYield = VALIDATION_CHUNK;
|
|
3284
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
3285
|
+
if (bytes[i] === 0) throw new Error(`NUL byte at byte offset ${i}; refusing binary input`);
|
|
3286
|
+
if (bytes[i] === 13) {
|
|
3287
|
+
if (bytes[i + 1] !== 10) throw new Error("Mixed or bare-CR line endings are unsupported; nothing was normalized");
|
|
3288
|
+
crlf = true;
|
|
3289
|
+
i += 1;
|
|
3290
|
+
} else if (bytes[i] === 10) lf = true;
|
|
3291
|
+
if (crlf && lf) throw new Error("Mixed or bare-CR line endings are unsupported; nothing was normalized");
|
|
3292
|
+
if (i >= nextYield) {
|
|
3293
|
+
nextYield = i + VALIDATION_CHUNK;
|
|
3294
|
+
await yieldImmediate();
|
|
3295
|
+
}
|
|
3296
|
+
}
|
|
3297
|
+
return crlf ? "\r\n" : "\n";
|
|
3298
|
+
}
|
|
3299
|
+
function applyLargeExactEdits(content, edits, ending) {
|
|
3300
|
+
const matches = edits.map((edit, editIndex) => {
|
|
3301
|
+
const oldText = restoreLineEndings(normalizeToLF(edit.oldText), ending);
|
|
3302
|
+
if (!oldText) throw new Error(`edits[${editIndex}].oldText must not be empty`);
|
|
3303
|
+
const index = content.indexOf(oldText);
|
|
3304
|
+
if (index < 0)
|
|
3305
|
+
throw new Error("Files above 1 MiB require exact matches; fuzzy matching is skipped to bound allocation");
|
|
3306
|
+
if (content.indexOf(oldText, index + oldText.length) >= 0)
|
|
3307
|
+
throw new Error("The text must be unique; provide more context");
|
|
3308
|
+
return { index, length: oldText.length, replacement: restoreLineEndings(normalizeToLF(edit.newText), ending) };
|
|
3309
|
+
}).sort((a, b) => a.index - b.index);
|
|
3310
|
+
const pieces = [];
|
|
3311
|
+
let cursor = 0;
|
|
3312
|
+
for (const entry of matches) {
|
|
3313
|
+
if (entry.index < cursor) throw new Error("Edits overlap; target disjoint regions");
|
|
3314
|
+
pieces.push(content.slice(cursor, entry.index), entry.replacement);
|
|
3315
|
+
cursor = entry.index + entry.length;
|
|
3316
|
+
}
|
|
3317
|
+
pieces.push(content.slice(cursor));
|
|
3318
|
+
const result = pieces.join("");
|
|
3319
|
+
if (result === content) throw new Error("No changes made; replacements produced identical content");
|
|
3320
|
+
return result;
|
|
3321
|
+
}
|
|
2583
3322
|
var editEntrySchema = typebox_exports.Object({
|
|
2584
3323
|
oldText: typebox_exports.String({ description: "Exact unique text to replace; must not overlap other edits." }),
|
|
2585
3324
|
newText: typebox_exports.String({ description: "Replacement text." })
|
|
@@ -2618,7 +3357,7 @@ function prepareEditArguments(args) {
|
|
|
2618
3357
|
}
|
|
2619
3358
|
var editTool = {
|
|
2620
3359
|
name: ToolNames.Edit,
|
|
2621
|
-
description: "Edit one file with exact text replacements. Each oldText must match a unique region of the original file.",
|
|
3360
|
+
description: "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\u2019s 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.",
|
|
2622
3361
|
parameters: typebox_exports.Object({
|
|
2623
3362
|
path: typebox_exports.String({ description: "File path (relative or absolute)." }),
|
|
2624
3363
|
edits: typebox_exports.Array(editEntrySchema, { description: "One or more targeted replacements." })
|
|
@@ -2637,21 +3376,39 @@ var editTool = {
|
|
|
2637
3376
|
const filePath = resolveToCwd(pathArg);
|
|
2638
3377
|
try {
|
|
2639
3378
|
return await withFileMutationQueue(filePath, async () => {
|
|
2640
|
-
const
|
|
3379
|
+
const info = await stat2(filePath);
|
|
3380
|
+
if (!info.isFile()) throw new Error("Refusing directory or non-file target");
|
|
3381
|
+
const bytes = await readFile(filePath);
|
|
3382
|
+
const originalEnding = await classifyEndings(bytes);
|
|
3383
|
+
let rawContent;
|
|
3384
|
+
try {
|
|
3385
|
+
rawContent = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
|
|
3386
|
+
} catch {
|
|
3387
|
+
throw new Error(`Invalid UTF-8 at byte offset ${await invalidUtf8Offset(bytes)}`);
|
|
3388
|
+
}
|
|
2641
3389
|
const { bom, text: content } = stripBom(rawContent);
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
3390
|
+
let finalContent;
|
|
3391
|
+
let diff;
|
|
3392
|
+
if (bytes.length > DIFF_LIMIT) {
|
|
3393
|
+
finalContent = bom + applyLargeExactEdits(content, edits, originalEnding);
|
|
3394
|
+
} else {
|
|
3395
|
+
const applied = applyEditsToNormalizedContent(normalizeToLF(content), edits, pathArg);
|
|
3396
|
+
finalContent = bom + restoreLineEndings(applied.newContent, originalEnding);
|
|
3397
|
+
if (Buffer.byteLength(finalContent, "utf8") <= DIFF_LIMIT) {
|
|
3398
|
+
diff = generateDiffString(applied.baseContent, applied.newContent);
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
const file = await publishFileAtomically(filePath, finalContent);
|
|
2651
3402
|
return {
|
|
2652
3403
|
kind: "ok",
|
|
2653
|
-
output: `edited ${pathArg}: ${
|
|
2654
|
-
|
|
3404
|
+
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 ? `
|
|
3405
|
+
${file.durabilityWarning}` : ""}`,
|
|
3406
|
+
details: {
|
|
3407
|
+
file: { before: file.before, after: file.after },
|
|
3408
|
+
diff: diff?.diff,
|
|
3409
|
+
firstChangedLine: diff?.firstChangedLine,
|
|
3410
|
+
paths: [filePath]
|
|
3411
|
+
}
|
|
2655
3412
|
};
|
|
2656
3413
|
});
|
|
2657
3414
|
} catch (err) {
|
|
@@ -2660,10 +3417,10 @@ var editTool = {
|
|
|
2660
3417
|
if (code === "ENOENT") {
|
|
2661
3418
|
return {
|
|
2662
3419
|
kind: "error",
|
|
2663
|
-
message: `edit: ${msg}. File not found at ${pathArg}. The path may be wrong. Try: code_nav, find, glob, or ls to locate it.`
|
|
3420
|
+
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.`
|
|
2664
3421
|
};
|
|
2665
3422
|
}
|
|
2666
|
-
return { kind: "error", message: `edit: ${msg}` };
|
|
3423
|
+
return { kind: "error", message: `edit: Nothing was published. ${msg}` };
|
|
2667
3424
|
}
|
|
2668
3425
|
}
|
|
2669
3426
|
};
|
|
@@ -2705,7 +3462,7 @@ var evidenceTool = {
|
|
|
2705
3462
|
try {
|
|
2706
3463
|
const dataDir = clioDataDir();
|
|
2707
3464
|
if (mode === "list") {
|
|
2708
|
-
const { evidenceInventorySnapshot } = await import("./inventory-
|
|
3465
|
+
const { evidenceInventorySnapshot } = await import("./inventory-I6VJDDYF.js");
|
|
2709
3466
|
return boundedResult(await evidenceInventorySnapshot(Date.now, dataDir));
|
|
2710
3467
|
}
|
|
2711
3468
|
const id = mode === "inspect" ? args.id : args.runId;
|
|
@@ -2713,8 +3470,8 @@ var evidenceTool = {
|
|
|
2713
3470
|
return { kind: "error", message: `evidence: ${mode} requires ${mode === "inspect" ? "id" : "runId"}` };
|
|
2714
3471
|
}
|
|
2715
3472
|
assertSafeId(id, mode === "inspect" ? "evidence" : "run");
|
|
2716
|
-
const { buildEvidence, EvidenceNotFoundError, inspectEvidence, loadEvidenceGateDecisions } = await import("./evidence-
|
|
2717
|
-
const { evidenceDetailSnapshot } = await import("./detail-
|
|
3473
|
+
const { buildEvidence, EvidenceNotFoundError, inspectEvidence, loadEvidenceGateDecisions } = await import("./evidence-P4NZOAK7.js");
|
|
3474
|
+
const { evidenceDetailSnapshot } = await import("./detail-4GLROGY5.js");
|
|
2718
3475
|
let evidenceId = mode === "run" ? `run-${id}` : id;
|
|
2719
3476
|
let inspected;
|
|
2720
3477
|
try {
|
|
@@ -2754,15 +3511,58 @@ var evidenceTool = {
|
|
|
2754
3511
|
init_esm_shims();
|
|
2755
3512
|
import { existsSync, statSync } from "node:fs";
|
|
2756
3513
|
import { readdir } from "node:fs/promises";
|
|
2757
|
-
import { join, relative } from "node:path";
|
|
3514
|
+
import { join as join2, relative, resolve as resolve2 } from "node:path";
|
|
2758
3515
|
|
|
2759
3516
|
// src/tools/spawn-hygiene.ts
|
|
2760
3517
|
init_esm_shims();
|
|
3518
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2761
3519
|
import { spawn } from "node:child_process";
|
|
2762
3520
|
import { createInterface as createInterface2 } from "node:readline";
|
|
3521
|
+
import { StringDecoder } from "node:string_decoder";
|
|
2763
3522
|
var SEARCH_SPAWN_TIMEOUT_MS = 3e4;
|
|
2764
3523
|
var KILL_GRACE_MS = 3e3;
|
|
2765
|
-
var
|
|
3524
|
+
var SEARCH_STDERR_CAP_BYTES = 16 * 1024;
|
|
3525
|
+
var timeoutContext = new AsyncLocalStorage();
|
|
3526
|
+
function decodeBoundedUtf8(buffer) {
|
|
3527
|
+
const decoded = new StringDecoder("utf8").write(buffer);
|
|
3528
|
+
return truncateUtf8(decoded, SEARCH_STDERR_CAP_BYTES, "");
|
|
3529
|
+
}
|
|
3530
|
+
var BoundedDiagnosticDecoder = class {
|
|
3531
|
+
constructor(onLine) {
|
|
3532
|
+
this.onLine = onLine;
|
|
3533
|
+
}
|
|
3534
|
+
onLine;
|
|
3535
|
+
buffer = Buffer.alloc(SEARCH_STDERR_CAP_BYTES);
|
|
3536
|
+
used = 0;
|
|
3537
|
+
truncated = false;
|
|
3538
|
+
oversizedLines = 0;
|
|
3539
|
+
get bufferedBytes() {
|
|
3540
|
+
return this.used;
|
|
3541
|
+
}
|
|
3542
|
+
write(chunk) {
|
|
3543
|
+
let start = 0;
|
|
3544
|
+
while (start < chunk.length) {
|
|
3545
|
+
const newline = chunk.indexOf(10, start);
|
|
3546
|
+
const end = newline < 0 ? chunk.length : newline;
|
|
3547
|
+
const take = Math.min(end - start, this.buffer.length - this.used);
|
|
3548
|
+
chunk.copy(this.buffer, this.used, start, start + take);
|
|
3549
|
+
this.used += take;
|
|
3550
|
+
if (take < end - start) this.truncated = true;
|
|
3551
|
+
if (newline < 0) break;
|
|
3552
|
+
this.flush();
|
|
3553
|
+
start = newline + 1;
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
end() {
|
|
3557
|
+
if (this.used || this.truncated) this.flush();
|
|
3558
|
+
}
|
|
3559
|
+
flush() {
|
|
3560
|
+
if (this.truncated) this.oversizedLines++;
|
|
3561
|
+
this.onLine(decodeBoundedUtf8(this.buffer.subarray(0, this.used)).replace(/\r$/, ""), this.truncated);
|
|
3562
|
+
this.used = 0;
|
|
3563
|
+
this.truncated = false;
|
|
3564
|
+
}
|
|
3565
|
+
};
|
|
2766
3566
|
var MAX_SEARCH_PATTERN_BYTES = 64 * 1024;
|
|
2767
3567
|
function validateSearchPatternSize(pattern) {
|
|
2768
3568
|
const bytes = Buffer.byteLength(pattern, "utf8");
|
|
@@ -2772,15 +3572,76 @@ function validateSearchPatternSize(pattern) {
|
|
|
2772
3572
|
message: `pattern too large (${bytes} bytes; max ${MAX_SEARCH_PATTERN_BYTES}). Narrow the pattern before searching.`
|
|
2773
3573
|
};
|
|
2774
3574
|
}
|
|
3575
|
+
function newSearchCompleteness() {
|
|
3576
|
+
return { complete: true, skipped: { count: 0, samples: [] } };
|
|
3577
|
+
}
|
|
3578
|
+
function skipSearchPath(search, path5, allows = () => true) {
|
|
3579
|
+
search.complete = false;
|
|
3580
|
+
search.reason ??= "errors";
|
|
3581
|
+
search.skipped.count += 1;
|
|
3582
|
+
if (allows(path5) && search.skipped.samples.length < 5) search.skipped.samples.push(path5);
|
|
3583
|
+
}
|
|
3584
|
+
function searchDiagnosticPath(line) {
|
|
3585
|
+
const cleaned = line.replace(/^(?:rg: |\[fd error\]:? )/, "").replace(/^IO error for operation on /, "");
|
|
3586
|
+
if (/^(?:regex parse error|error parsing (?:glob|regex)|invalid (?:glob|regex)|error:|Usage:)/i.test(cleaned))
|
|
3587
|
+
return null;
|
|
3588
|
+
const match = /^((?:[A-Za-z]:[\\/])?[^\r\n]+?):(?:\s|$)/.exec(cleaned);
|
|
3589
|
+
return match?.[1] ?? null;
|
|
3590
|
+
}
|
|
3591
|
+
function createSearchDiagnostics(search, allows) {
|
|
3592
|
+
let continuation = false;
|
|
3593
|
+
let realError = false;
|
|
3594
|
+
return {
|
|
3595
|
+
get realError() {
|
|
3596
|
+
return realError;
|
|
3597
|
+
},
|
|
3598
|
+
onLine(line, truncated = false) {
|
|
3599
|
+
if (truncated) {
|
|
3600
|
+
search.skipped.unknown = true;
|
|
3601
|
+
search.complete = false;
|
|
3602
|
+
search.reason ??= "errors";
|
|
3603
|
+
}
|
|
3604
|
+
if (!line.trim()) return;
|
|
3605
|
+
if (continuation && /^\s/.test(line)) return;
|
|
3606
|
+
const path5 = searchDiagnosticPath(line);
|
|
3607
|
+
if (path5) {
|
|
3608
|
+
skipSearchPath(search, path5, allows);
|
|
3609
|
+
continuation = true;
|
|
3610
|
+
return;
|
|
3611
|
+
}
|
|
3612
|
+
if (continuation && /\(os error \d+\)/.test(line)) return;
|
|
3613
|
+
continuation = false;
|
|
3614
|
+
if (/^(?:rg: |\[fd error\]:? )?(?:regex parse error|error parsing (?:glob|regex)|invalid (?:glob|regex)|error:|Usage:)/i.test(
|
|
3615
|
+
line
|
|
3616
|
+
))
|
|
3617
|
+
realError = true;
|
|
3618
|
+
else search.skipped.unknown = true;
|
|
3619
|
+
search.complete = false;
|
|
3620
|
+
search.reason ??= "errors";
|
|
3621
|
+
}
|
|
3622
|
+
};
|
|
3623
|
+
}
|
|
3624
|
+
function finishSearch(search, result) {
|
|
3625
|
+
const reason = result.aborted ? "cancelled" : result.timedOut ? "timeout" : result.stoppedEarly ? "limit" : result.exitCode !== 0 && result.exitCode !== 1 ? "errors" : search.reason;
|
|
3626
|
+
if (reason) {
|
|
3627
|
+
search.complete = false;
|
|
3628
|
+
search.reason = reason;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
function searchNotice(search, shown, unit) {
|
|
3632
|
+
return search.complete ? "" : `
|
|
3633
|
+
[Search incomplete: ${search.reason}; ${shown} ${unit} shown; ${search.skipped.count}${search.skipped.unknown ? "+ (diagnostic coverage unknown)" : ""} paths skipped.]`;
|
|
3634
|
+
}
|
|
2775
3635
|
function spawnLineStream(file, args, options) {
|
|
2776
|
-
return new Promise((
|
|
2777
|
-
const timeoutMs = options.timeoutMs ?? SEARCH_SPAWN_TIMEOUT_MS;
|
|
3636
|
+
return new Promise((resolve3) => {
|
|
3637
|
+
const timeoutMs = options.timeoutMs ?? timeoutContext.getStore() ?? SEARCH_SPAWN_TIMEOUT_MS;
|
|
2778
3638
|
let timedOut = false;
|
|
2779
3639
|
let aborted = false;
|
|
2780
3640
|
let stoppedEarly = false;
|
|
2781
3641
|
let killSent = false;
|
|
2782
3642
|
let settled = false;
|
|
2783
|
-
|
|
3643
|
+
const retainedStderr = Buffer.alloc(SEARCH_STDERR_CAP_BYTES);
|
|
3644
|
+
let stderrBytes = 0;
|
|
2784
3645
|
let killGraceTimer = null;
|
|
2785
3646
|
const spawned = (() => {
|
|
2786
3647
|
try {
|
|
@@ -2798,9 +3659,10 @@ function spawnLineStream(file, args, options) {
|
|
|
2798
3659
|
}
|
|
2799
3660
|
})();
|
|
2800
3661
|
if (!spawned.ok) {
|
|
2801
|
-
|
|
3662
|
+
resolve3({
|
|
2802
3663
|
exitCode: null,
|
|
2803
3664
|
stderr: "",
|
|
3665
|
+
oversizedDiagnostics: 0,
|
|
2804
3666
|
timedOut: false,
|
|
2805
3667
|
aborted: false,
|
|
2806
3668
|
stoppedEarly: false,
|
|
@@ -2810,6 +3672,7 @@ function spawnLineStream(file, args, options) {
|
|
|
2810
3672
|
}
|
|
2811
3673
|
const child = spawned.child;
|
|
2812
3674
|
const rl = createInterface2({ input: child.stdout });
|
|
3675
|
+
const stderrLines = new BoundedDiagnosticDecoder((line, truncated) => options.onStderrLine?.(line, truncated));
|
|
2813
3676
|
const sendSignal = (signalName) => {
|
|
2814
3677
|
const pid = child.pid;
|
|
2815
3678
|
if (pid && process.platform !== "win32") {
|
|
@@ -2851,9 +3714,11 @@ function spawnLineStream(file, args, options) {
|
|
|
2851
3714
|
if (killGraceTimer) clearTimeout(killGraceTimer);
|
|
2852
3715
|
options.signal?.removeEventListener("abort", onAbort);
|
|
2853
3716
|
rl.close();
|
|
2854
|
-
|
|
3717
|
+
stderrLines.end();
|
|
3718
|
+
resolve3({
|
|
2855
3719
|
exitCode: child.exitCode,
|
|
2856
|
-
stderr,
|
|
3720
|
+
stderr: decodeBoundedUtf8(retainedStderr.subarray(0, stderrBytes)),
|
|
3721
|
+
oversizedDiagnostics: stderrLines.oversizedLines,
|
|
2857
3722
|
timedOut,
|
|
2858
3723
|
aborted,
|
|
2859
3724
|
stoppedEarly,
|
|
@@ -2865,7 +3730,10 @@ function spawnLineStream(file, args, options) {
|
|
|
2865
3730
|
options.onLine(line, stop);
|
|
2866
3731
|
});
|
|
2867
3732
|
child.stderr?.on("data", (chunk) => {
|
|
2868
|
-
|
|
3733
|
+
const take = Math.min(chunk.length, retainedStderr.length - stderrBytes);
|
|
3734
|
+
chunk.copy(retainedStderr, stderrBytes, 0, take);
|
|
3735
|
+
stderrBytes += take;
|
|
3736
|
+
stderrLines.write(chunk);
|
|
2869
3737
|
});
|
|
2870
3738
|
child.on("error", (error) => finish(error.message));
|
|
2871
3739
|
child.on("close", () => finish(null));
|
|
@@ -2875,9 +3743,9 @@ function spawnLineStream(file, args, options) {
|
|
|
2875
3743
|
// src/tools/find.ts
|
|
2876
3744
|
var DEFAULT_LIMIT = 500;
|
|
2877
3745
|
var MTIME_CANDIDATE_FLOOR = 2e3;
|
|
2878
|
-
function buildFdArgs(pattern, searchPath,
|
|
3746
|
+
function buildFdArgs(pattern, searchPath, collectLimit, includeIgnored) {
|
|
2879
3747
|
const args = ["--glob", "--color=never", ...fdIgnoreArgs(searchPath, includeIgnored)];
|
|
2880
|
-
args.push("--max-results", String(
|
|
3748
|
+
args.push("--show-errors", "--max-results", String(collectLimit));
|
|
2881
3749
|
let effectivePattern = pattern;
|
|
2882
3750
|
if (pattern.includes("/")) {
|
|
2883
3751
|
args.push("--full-path");
|
|
@@ -2888,35 +3756,38 @@ function buildFdArgs(pattern, searchPath, maxResults, includeIgnored) {
|
|
|
2888
3756
|
args.push("--", effectivePattern, searchPath);
|
|
2889
3757
|
return args;
|
|
2890
3758
|
}
|
|
2891
|
-
async function fdFind(fdPath, pattern, searchPath, collectLimit, includeIgnored, signal) {
|
|
3759
|
+
async function fdFind(fdPath, pattern, searchPath, collectLimit, includeIgnored, search, allows, signal) {
|
|
2892
3760
|
const lines = [];
|
|
3761
|
+
const diagnostics = createSearchDiagnostics(search, (path5) => allows(resolve2(process.cwd(), path5)));
|
|
2893
3762
|
const result = await spawnLineStream(fdPath, buildFdArgs(pattern, searchPath, collectLimit, includeIgnored), {
|
|
2894
3763
|
...signal ? { signal } : {},
|
|
3764
|
+
onStderrLine: diagnostics.onLine,
|
|
2895
3765
|
onLine(line, stop) {
|
|
2896
3766
|
lines.push(line);
|
|
2897
3767
|
if (lines.length >= collectLimit) stop();
|
|
2898
3768
|
}
|
|
2899
3769
|
});
|
|
2900
|
-
|
|
2901
|
-
if (result.timedOut) {
|
|
3770
|
+
finishSearch(search, result);
|
|
3771
|
+
if (!result.aborted && !result.timedOut && !result.stoppedEarly && result.exitCode !== 0) {
|
|
3772
|
+
search.complete = false;
|
|
3773
|
+
search.reason = "errors";
|
|
3774
|
+
}
|
|
3775
|
+
if (result.spawnError !== null) return { ok: false, message: `find: failed to run fd: ${result.spawnError}` };
|
|
3776
|
+
if (!result.aborted && !result.timedOut && !result.stoppedEarly && result.exitCode !== 0 && lines.length === 0 && (diagnostics.realError || search.skipped.count === 0 && !search.skipped.unknown)) {
|
|
2902
3777
|
return {
|
|
2903
3778
|
ok: false,
|
|
2904
|
-
message: `find: fd
|
|
3779
|
+
message: `find: fd rejected the search or failed (exit code ${result.exitCode}). Check the glob and search path.`
|
|
2905
3780
|
};
|
|
2906
3781
|
}
|
|
2907
|
-
|
|
2908
|
-
if (!result.stoppedEarly && result.exitCode !== 0 && lines.length === 0) {
|
|
2909
|
-
return { ok: false, message: `find: ${result.stderr.trim() || `fd exited with code ${result.exitCode}`}` };
|
|
2910
|
-
}
|
|
2911
|
-
const paths = lines.map((rawLine) => rawLine.replace(/\r$/, "").trim()).filter((line) => line.length > 0).map((line) => {
|
|
3782
|
+
const paths = lines.map((rawLine) => rawLine.replace(/\r$/, "")).filter((line) => line.length > 0).map((line) => {
|
|
2912
3783
|
const hadTrailingSlash = line.endsWith("/") || line.endsWith("\\");
|
|
2913
|
-
let relPath =
|
|
3784
|
+
let relPath = relative(searchPath, line);
|
|
2914
3785
|
if (hadTrailingSlash && !relPath.endsWith("/")) relPath += "/";
|
|
2915
3786
|
return toPosixPath(relPath);
|
|
2916
3787
|
});
|
|
2917
3788
|
return { ok: true, paths };
|
|
2918
3789
|
}
|
|
2919
|
-
async function fallbackFind(pattern, searchPath, collectLimit, includeIgnored, signal) {
|
|
3790
|
+
async function fallbackFind(pattern, searchPath, collectLimit, includeIgnored, search, allows, signal) {
|
|
2920
3791
|
const matcher = compileGlobRegex(pattern.includes("/") ? pattern : `**/${pattern}`);
|
|
2921
3792
|
const ignored = fallbackIgnoredDirs(includeIgnored);
|
|
2922
3793
|
const out = [];
|
|
@@ -2926,11 +3797,13 @@ async function fallbackFind(pattern, searchPath, collectLimit, includeIgnored, s
|
|
|
2926
3797
|
try {
|
|
2927
3798
|
entries = (await readdir(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
2928
3799
|
} catch {
|
|
3800
|
+
skipSearchPath(search, dir, allows);
|
|
2929
3801
|
return;
|
|
2930
3802
|
}
|
|
2931
3803
|
for (const entry of entries) {
|
|
2932
3804
|
if (out.length >= collectLimit || signal?.aborted) return;
|
|
2933
|
-
const absPath =
|
|
3805
|
+
const absPath = join2(dir, entry.name);
|
|
3806
|
+
if (!allows(absPath)) continue;
|
|
2934
3807
|
if (entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
2935
3808
|
if (ignored.has(entry.name)) continue;
|
|
2936
3809
|
const relDir = `${toPosixPath(relative(searchPath, absPath))}/`;
|
|
@@ -2938,7 +3811,13 @@ async function fallbackFind(pattern, searchPath, collectLimit, includeIgnored, s
|
|
|
2938
3811
|
await walk(absPath);
|
|
2939
3812
|
continue;
|
|
2940
3813
|
}
|
|
2941
|
-
if (
|
|
3814
|
+
if (entry.isSymbolicLink()) {
|
|
3815
|
+
try {
|
|
3816
|
+
if (statSync(absPath).isDirectory()) skipSearchPath(search, absPath, allows);
|
|
3817
|
+
} catch {
|
|
3818
|
+
skipSearchPath(search, absPath, allows);
|
|
3819
|
+
}
|
|
3820
|
+
} else if (!entry.isFile()) continue;
|
|
2942
3821
|
const relPath = toPosixPath(relative(searchPath, absPath));
|
|
2943
3822
|
if (matcher.test(normalizeGlobInput(relPath))) out.push(relPath);
|
|
2944
3823
|
}
|
|
@@ -2946,13 +3825,14 @@ async function fallbackFind(pattern, searchPath, collectLimit, includeIgnored, s
|
|
|
2946
3825
|
await walk(searchPath);
|
|
2947
3826
|
return out;
|
|
2948
3827
|
}
|
|
2949
|
-
function orderByMtime(paths, searchPath, limit, candidateCap) {
|
|
3828
|
+
function orderByMtime(paths, searchPath, limit, candidateCap, search) {
|
|
2950
3829
|
const candidateCapHit = paths.length >= candidateCap;
|
|
2951
3830
|
const stamped = paths.map((relPath) => {
|
|
2952
3831
|
let mtimeMs = 0;
|
|
2953
3832
|
try {
|
|
2954
|
-
mtimeMs = statSync(
|
|
3833
|
+
mtimeMs = statSync(join2(searchPath, relPath)).mtimeMs;
|
|
2955
3834
|
} catch {
|
|
3835
|
+
skipSearchPath(search, join2(searchPath, relPath));
|
|
2956
3836
|
}
|
|
2957
3837
|
return { relPath, mtimeMs };
|
|
2958
3838
|
});
|
|
@@ -2960,16 +3840,22 @@ function orderByMtime(paths, searchPath, limit, candidateCap) {
|
|
|
2960
3840
|
return { paths: stamped.slice(0, limit).map((entry) => entry.relPath), candidateCapHit, candidateCap };
|
|
2961
3841
|
}
|
|
2962
3842
|
function renderFindResult(input) {
|
|
2963
|
-
const { ordered, collected, collectLimit, limit, order, reservation, options } = input;
|
|
3843
|
+
const { ordered, collected, collectLimit, limit, order, reservation, options, search } = input;
|
|
3844
|
+
if ((collected > limit || collected >= collectLimit || ordered.candidateCapHit) && search.complete) {
|
|
3845
|
+
search.complete = false;
|
|
3846
|
+
search.reason = "limit";
|
|
3847
|
+
}
|
|
3848
|
+
const coverageNotice = input.fallback ? "\n[Fallback search uses GENERATED_DIRS only; .gitignore is not applied.]" : "\n[Native fd search: skipped symlinked directories are not counted.]";
|
|
2964
3849
|
if (ordered.paths.length === 0) {
|
|
2965
3850
|
return finalizeObservation({
|
|
2966
3851
|
tool: ToolNames.Find,
|
|
2967
3852
|
withheldPaths: input.withheldPaths,
|
|
2968
3853
|
unit: "paths",
|
|
2969
|
-
output: "No visible files found matching pattern",
|
|
3854
|
+
output: (search.complete ? "No visible files found matching pattern" : "Search incomplete") + searchNotice(search, 0, "paths") + coverageNotice,
|
|
3855
|
+
details: { search, symlinkDirectories: { counted: input.fallback } },
|
|
2970
3856
|
shownCount: 0,
|
|
2971
|
-
totalCount:
|
|
2972
|
-
truncated:
|
|
3857
|
+
totalCount: search.complete ? 0 : null,
|
|
3858
|
+
truncated: !search.complete,
|
|
2973
3859
|
...collected >= collectLimit ? { next: `limit=${limit * 2}` } : {},
|
|
2974
3860
|
reservation,
|
|
2975
3861
|
...options ? { options } : {}
|
|
@@ -2981,10 +3867,14 @@ function renderFindResult(input) {
|
|
|
2981
3867
|
maxLines: Number.MAX_SAFE_INTEGER
|
|
2982
3868
|
});
|
|
2983
3869
|
const limitHit = collected > limit || collected >= collectLimit;
|
|
2984
|
-
|
|
2985
|
-
|
|
3870
|
+
if (truncation.truncated && search.complete) {
|
|
3871
|
+
search.complete = false;
|
|
3872
|
+
search.reason = "limit";
|
|
3873
|
+
}
|
|
3874
|
+
const totalKnown = search.complete;
|
|
3875
|
+
const truncated = !search.complete || limitHit || ordered.candidateCapHit || truncation.truncated;
|
|
2986
3876
|
const next = limitHit ? `limit=${limit * 2}` : ordered.candidateCapHit ? "order=path" : void 0;
|
|
2987
|
-
const details = {};
|
|
3877
|
+
const details = { search, symlinkDirectories: { counted: input.fallback } };
|
|
2988
3878
|
if (order === "mtime" && ordered.candidateCap !== null) {
|
|
2989
3879
|
details.candidates = {
|
|
2990
3880
|
cap: ordered.candidateCap,
|
|
@@ -2997,7 +3887,7 @@ function renderFindResult(input) {
|
|
|
2997
3887
|
tool: ToolNames.Find,
|
|
2998
3888
|
withheldPaths: input.withheldPaths,
|
|
2999
3889
|
unit: "paths",
|
|
3000
|
-
output: truncation.content,
|
|
3890
|
+
output: truncation.content + searchNotice(search, truncation.outputLines, "paths") + coverageNotice,
|
|
3001
3891
|
// Offload only when the byte cap cut collected paths; a bare result
|
|
3002
3892
|
// limit continues via `next`, and the offload would duplicate the body.
|
|
3003
3893
|
...truncation.truncated ? { fullOutput } : {},
|
|
@@ -3012,7 +3902,7 @@ function renderFindResult(input) {
|
|
|
3012
3902
|
}
|
|
3013
3903
|
var findTool = {
|
|
3014
3904
|
name: ToolNames.Find,
|
|
3015
|
-
description: "Find files and directories by glob pattern (supports *, **, ?, [abc]); returns paths relative to the search directory. Respects .gitignore and skips generated dirs (node_modules, dist, build, ...) unless include_ignored=true. order=path (default) returns fd's native order; order=mtime returns newest first from a bounded candidate set. Truncated results say how to continue and where the full list was saved.",
|
|
3905
|
+
description: "Find files and directories by glob pattern (supports *, **, ?, [abc]); returns paths relative to the search directory. Respects .gitignore and skips generated dirs (node_modules, dist, build, ...) unless include_ignored=true. Symlinked directories are never followed. Only the fallback counts skipped symlinked directories; native fd leaves that count unmeasured, as indicated by details.symlinkDirectories.counted=false. Without fd the fallback uses GENERATED_DIRS only, with no .gitignore support. order=path (default) returns fd's native order; order=mtime returns newest first from a bounded candidate set. Truncated results say how to continue and where the full list was saved.",
|
|
3016
3906
|
parameters: typebox_exports.Object({
|
|
3017
3907
|
pattern: typebox_exports.String({ description: "Glob pattern, e.g. 'src/**/*.ts'." }),
|
|
3018
3908
|
path: typebox_exports.Optional(typebox_exports.String({ description: "Directory to search in." })),
|
|
@@ -3052,24 +3942,48 @@ var findTool = {
|
|
|
3052
3942
|
commitObservationReservation(reservation);
|
|
3053
3943
|
try {
|
|
3054
3944
|
let collectedPaths;
|
|
3945
|
+
const search = newSearchCompleteness();
|
|
3946
|
+
const pathFilter = createObservationPathFilter(process.cwd(), options?.allowsObservationPath);
|
|
3055
3947
|
const fdPath = resolveFdBinary();
|
|
3056
3948
|
if (fdPath) {
|
|
3057
|
-
const result = await fdFind(
|
|
3949
|
+
const result = await fdFind(
|
|
3950
|
+
fdPath,
|
|
3951
|
+
pattern,
|
|
3952
|
+
searchPath,
|
|
3953
|
+
collectLimit,
|
|
3954
|
+
includeIgnored,
|
|
3955
|
+
search,
|
|
3956
|
+
pathFilter.allows,
|
|
3957
|
+
options?.signal
|
|
3958
|
+
);
|
|
3058
3959
|
if (!result.ok) return { kind: "error", message: result.message };
|
|
3059
3960
|
collectedPaths = result.paths;
|
|
3060
3961
|
} else {
|
|
3061
3962
|
try {
|
|
3062
|
-
collectedPaths = await fallbackFind(
|
|
3963
|
+
collectedPaths = await fallbackFind(
|
|
3964
|
+
pattern,
|
|
3965
|
+
searchPath,
|
|
3966
|
+
collectLimit,
|
|
3967
|
+
includeIgnored,
|
|
3968
|
+
search,
|
|
3969
|
+
pathFilter.allows,
|
|
3970
|
+
options?.signal
|
|
3971
|
+
);
|
|
3063
3972
|
} catch (err) {
|
|
3064
3973
|
const message = err instanceof Error ? err.message : String(err);
|
|
3065
3974
|
return { kind: "error", message: `find: ${message}` };
|
|
3066
3975
|
}
|
|
3067
3976
|
}
|
|
3977
|
+
if (options?.signal?.aborted) {
|
|
3978
|
+
search.complete = false;
|
|
3979
|
+
search.reason = "cancelled";
|
|
3980
|
+
}
|
|
3068
3981
|
const collectedCount = collectedPaths.length;
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
const ordered = order === "mtime" ? orderByMtime(collectedPaths, searchPath, limit, collectLimit) : { paths: collectedPaths.slice(0, limit), candidateCapHit: false, candidateCap: null };
|
|
3982
|
+
collectedPaths = collectedPaths.filter((entry) => pathFilter.allows(join2(searchPath, entry)));
|
|
3983
|
+
const ordered = order === "mtime" ? orderByMtime(collectedPaths, searchPath, limit, collectLimit, search) : { paths: collectedPaths.slice(0, limit), candidateCapHit: false, candidateCap: null };
|
|
3072
3984
|
return renderFindResult({
|
|
3985
|
+
search,
|
|
3986
|
+
fallback: !fdPath,
|
|
3073
3987
|
withheldPaths: pathFilter.withheldPaths,
|
|
3074
3988
|
ordered,
|
|
3075
3989
|
collected: collectedCount,
|
|
@@ -3087,8 +4001,10 @@ var findTool = {
|
|
|
3087
4001
|
|
|
3088
4002
|
// src/tools/grep.ts
|
|
3089
4003
|
init_esm_shims();
|
|
3090
|
-
import {
|
|
3091
|
-
import
|
|
4004
|
+
import { statSync as statSync2 } from "node:fs";
|
|
4005
|
+
import { readdir as readdir2, readFile as readFile2, stat as stat3 } from "node:fs/promises";
|
|
4006
|
+
import path2, { join as join3, relative as relative2 } from "node:path";
|
|
4007
|
+
import { setImmediate as yieldToLoop } from "node:timers/promises";
|
|
3092
4008
|
var DEFAULT_LIMIT2 = 100;
|
|
3093
4009
|
var FALLBACK_MAX_FILE_BYTES = 2e7;
|
|
3094
4010
|
var MODE_UNITS = {
|
|
@@ -3118,16 +4034,18 @@ function statIsDirectory(searchPath) {
|
|
|
3118
4034
|
}
|
|
3119
4035
|
var NO_MATCH_OUTPUT = "No matches found";
|
|
3120
4036
|
function renderGrepResult(input) {
|
|
3121
|
-
const { mode, lines, matchCount, limitHit, limit, linesTruncated, reservation, options } = input;
|
|
4037
|
+
const { mode, lines, matchCount, limitHit, limit, linesTruncated, reservation, options, search } = input;
|
|
4038
|
+
const fallbackNotice = input.fallback ? "\n[Fallback search uses GENERATED_DIRS only; .gitignore is not applied.]" : "";
|
|
3122
4039
|
if (lines.length === 0) {
|
|
3123
4040
|
return finalizeObservation({
|
|
3124
4041
|
tool: ToolNames.Grep,
|
|
3125
4042
|
withheldPaths: input.withheldPaths,
|
|
3126
4043
|
unit: MODE_UNITS[mode],
|
|
3127
|
-
output: NO_MATCH_OUTPUT,
|
|
4044
|
+
output: (search.complete ? NO_MATCH_OUTPUT : "Search incomplete") + searchNotice(search, 0, "matches") + fallbackNotice,
|
|
4045
|
+
details: { search },
|
|
3128
4046
|
shownCount: 0,
|
|
3129
|
-
totalCount: 0,
|
|
3130
|
-
truncated:
|
|
4047
|
+
totalCount: search.complete ? 0 : null,
|
|
4048
|
+
truncated: !search.complete,
|
|
3131
4049
|
reservation,
|
|
3132
4050
|
...options ? { options } : {}
|
|
3133
4051
|
});
|
|
@@ -3143,7 +4061,11 @@ function renderGrepResult(input) {
|
|
|
3143
4061
|
} else {
|
|
3144
4062
|
shownCount = truncation.outputLines;
|
|
3145
4063
|
}
|
|
3146
|
-
|
|
4064
|
+
if (truncation.truncated && search.complete) {
|
|
4065
|
+
search.complete = false;
|
|
4066
|
+
search.reason = "limit";
|
|
4067
|
+
}
|
|
4068
|
+
const truncated = !search.complete || limitHit || truncation.truncated;
|
|
3147
4069
|
const next = limitHit ? `limit=${limit * 2}` : truncation.truncated && mode === "content" ? "mode=files" : void 0;
|
|
3148
4070
|
let output = truncation.content;
|
|
3149
4071
|
if (linesTruncated) {
|
|
@@ -3155,12 +4077,13 @@ function renderGrepResult(input) {
|
|
|
3155
4077
|
tool: ToolNames.Grep,
|
|
3156
4078
|
withheldPaths: input.withheldPaths,
|
|
3157
4079
|
unit: MODE_UNITS[mode],
|
|
3158
|
-
output,
|
|
4080
|
+
output: output + searchNotice(search, shownCount, "matches") + fallbackNotice,
|
|
4081
|
+
details: { search },
|
|
3159
4082
|
// Offload only when the byte cap cut collected content; a bare match
|
|
3160
4083
|
// limit continues via `next`, and the offload would duplicate the body.
|
|
3161
4084
|
...truncation.truncated ? { fullOutput } : {},
|
|
3162
4085
|
shownCount,
|
|
3163
|
-
totalCount:
|
|
4086
|
+
totalCount: search.complete ? matchCount : null,
|
|
3164
4087
|
truncated,
|
|
3165
4088
|
...next !== void 0 ? { next } : {},
|
|
3166
4089
|
reservation,
|
|
@@ -3244,22 +4167,23 @@ async function runRipgrep(input) {
|
|
|
3244
4167
|
stop();
|
|
3245
4168
|
}
|
|
3246
4169
|
};
|
|
4170
|
+
const search = newSearchCompleteness();
|
|
4171
|
+
const diagnostics = createSearchDiagnostics(search, (filePath) => input.pathFilter.allows(path2.resolve(filePath)));
|
|
3247
4172
|
const result = await spawnLineStream(input.rgPath, buildRgArgs(input), {
|
|
3248
4173
|
...input.options?.signal ? { signal: input.options.signal } : {},
|
|
3249
|
-
onLine: input.mode === "content" ? onContentLine : onListLine
|
|
4174
|
+
onLine: input.mode === "content" ? onContentLine : onListLine,
|
|
4175
|
+
onStderrLine: diagnostics.onLine
|
|
3250
4176
|
});
|
|
3251
|
-
|
|
3252
|
-
if (result.
|
|
4177
|
+
finishSearch(search, result);
|
|
4178
|
+
if (result.spawnError !== null) return { kind: "error", message: `grep: failed to run rg: ${result.spawnError}` };
|
|
4179
|
+
if (!result.aborted && !result.timedOut && !result.stoppedEarly && result.exitCode !== 0 && result.exitCode !== 1 && matchCount === 0 && (diagnostics.realError || search.skipped.count === 0 && !search.skipped.unknown)) {
|
|
3253
4180
|
return {
|
|
3254
4181
|
kind: "error",
|
|
3255
|
-
message: `grep: rg
|
|
4182
|
+
message: `grep: rg rejected the search or failed (exit code ${result.exitCode}). Check the pattern and search path.`
|
|
3256
4183
|
};
|
|
3257
4184
|
}
|
|
3258
|
-
if (result.spawnError !== null) return { kind: "error", message: `grep: failed to run rg: ${result.spawnError}` };
|
|
3259
|
-
if (!result.stoppedEarly && result.exitCode !== 0 && result.exitCode !== 1) {
|
|
3260
|
-
return { kind: "error", message: `grep: ${result.stderr.trim() || `ripgrep exited with code ${result.exitCode}`}` };
|
|
3261
|
-
}
|
|
3262
4185
|
return renderGrepResult({
|
|
4186
|
+
search,
|
|
3263
4187
|
withheldPaths: input.pathFilter.withheldPaths,
|
|
3264
4188
|
mode: input.mode,
|
|
3265
4189
|
lines: rendered,
|
|
@@ -3287,7 +4211,8 @@ function looksBinary(buffer) {
|
|
|
3287
4211
|
}
|
|
3288
4212
|
return false;
|
|
3289
4213
|
}
|
|
3290
|
-
function fallbackGrep(input) {
|
|
4214
|
+
async function fallbackGrep(input) {
|
|
4215
|
+
const search = newSearchCompleteness();
|
|
3291
4216
|
const built = buildMatchRegex(input.pattern, input.literal, input.ignoreCase);
|
|
3292
4217
|
if (!built.ok) return { kind: "error", message: built.message };
|
|
3293
4218
|
const regex = built.regex;
|
|
@@ -3312,21 +4237,32 @@ function fallbackGrep(input) {
|
|
|
3312
4237
|
if (truncatedLine.wasTruncated) linesTruncated = true;
|
|
3313
4238
|
rendered.push({ text: truncatedLine.text, isMatch });
|
|
3314
4239
|
};
|
|
3315
|
-
const searchFile = (filePath) => {
|
|
3316
|
-
if (limitHit || !input.pathFilter.allows(filePath)) return;
|
|
4240
|
+
const searchFile = async (filePath) => {
|
|
4241
|
+
if (limitHit || signal?.aborted || !input.pathFilter.allows(filePath)) return;
|
|
3317
4242
|
let buffer;
|
|
3318
4243
|
try {
|
|
3319
|
-
const
|
|
3320
|
-
if (!
|
|
3321
|
-
|
|
4244
|
+
const fileStat = await stat3(filePath);
|
|
4245
|
+
if (!fileStat.isFile() || fileStat.size > FALLBACK_MAX_FILE_BYTES) {
|
|
4246
|
+
skipSearchPath(search, filePath, input.pathFilter.allows);
|
|
4247
|
+
return;
|
|
4248
|
+
}
|
|
4249
|
+
buffer = await readFile2(filePath);
|
|
3322
4250
|
} catch {
|
|
4251
|
+
skipSearchPath(search, filePath, input.pathFilter.allows);
|
|
4252
|
+
return;
|
|
4253
|
+
}
|
|
4254
|
+
if (looksBinary(buffer)) {
|
|
4255
|
+
skipSearchPath(search, filePath, input.pathFilter.allows);
|
|
3323
4256
|
return;
|
|
3324
4257
|
}
|
|
3325
|
-
if (looksBinary(buffer)) return;
|
|
3326
4258
|
const lines = buffer.toString("utf8").replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
|
|
3327
4259
|
const rel = formatPath(filePath, input.searchPath, input.isDirectory);
|
|
3328
4260
|
let fileMatches = 0;
|
|
3329
4261
|
for (let i = 0; i < lines.length; i += 1) {
|
|
4262
|
+
if (i % 1024 === 0) {
|
|
4263
|
+
await yieldToLoop();
|
|
4264
|
+
if (signal?.aborted) return;
|
|
4265
|
+
}
|
|
3330
4266
|
const lineText = lines[i] ?? "";
|
|
3331
4267
|
regex.lastIndex = 0;
|
|
3332
4268
|
if (!regex.test(lineText)) continue;
|
|
@@ -3358,34 +4294,45 @@ function fallbackGrep(input) {
|
|
|
3358
4294
|
if (matchCount >= input.limit) limitHit = true;
|
|
3359
4295
|
}
|
|
3360
4296
|
};
|
|
3361
|
-
const walk = (dir) => {
|
|
4297
|
+
const walk = async (dir) => {
|
|
4298
|
+
await yieldToLoop();
|
|
3362
4299
|
if (limitHit || signal?.aborted) return;
|
|
3363
4300
|
let entries;
|
|
3364
4301
|
try {
|
|
3365
|
-
entries =
|
|
4302
|
+
entries = (await readdir2(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
3366
4303
|
} catch {
|
|
4304
|
+
skipSearchPath(search, dir, input.pathFilter.allows);
|
|
3367
4305
|
return;
|
|
3368
4306
|
}
|
|
3369
4307
|
for (const entry of entries) {
|
|
3370
4308
|
if (limitHit || signal?.aborted) return;
|
|
3371
|
-
const absPath =
|
|
4309
|
+
const absPath = join3(dir, entry.name);
|
|
4310
|
+
if (!input.pathFilter.allows(absPath)) continue;
|
|
3372
4311
|
if (entry.isDirectory()) {
|
|
3373
4312
|
if (ignored.has(entry.name)) continue;
|
|
3374
|
-
walk(absPath);
|
|
4313
|
+
await walk(absPath);
|
|
4314
|
+
continue;
|
|
4315
|
+
}
|
|
4316
|
+
if (!entry.isFile()) {
|
|
4317
|
+
skipSearchPath(search, absPath, input.pathFilter.allows);
|
|
3375
4318
|
continue;
|
|
3376
4319
|
}
|
|
3377
|
-
if (!entry.isFile()) continue;
|
|
3378
4320
|
if (globMatcher) {
|
|
3379
4321
|
const relPath = normalizeGlobInput(relative2(input.searchPath, absPath));
|
|
3380
4322
|
if (!globMatcher.test(relPath)) continue;
|
|
3381
4323
|
}
|
|
3382
|
-
searchFile(absPath);
|
|
4324
|
+
await searchFile(absPath);
|
|
3383
4325
|
}
|
|
3384
4326
|
};
|
|
3385
|
-
if (input.isDirectory) walk(input.searchPath);
|
|
3386
|
-
else searchFile(input.searchPath);
|
|
3387
|
-
if (signal?.aborted)
|
|
4327
|
+
if (input.isDirectory) await walk(input.searchPath);
|
|
4328
|
+
else await searchFile(input.searchPath);
|
|
4329
|
+
if (signal?.aborted || limitHit) {
|
|
4330
|
+
search.complete = false;
|
|
4331
|
+
search.reason = signal?.aborted ? "cancelled" : "limit";
|
|
4332
|
+
}
|
|
3388
4333
|
return renderGrepResult({
|
|
4334
|
+
fallback: true,
|
|
4335
|
+
search,
|
|
3389
4336
|
withheldPaths: input.pathFilter.withheldPaths,
|
|
3390
4337
|
mode: input.mode,
|
|
3391
4338
|
lines: rendered,
|
|
@@ -3399,7 +4346,7 @@ function fallbackGrep(input) {
|
|
|
3399
4346
|
}
|
|
3400
4347
|
var grepTool = {
|
|
3401
4348
|
name: ToolNames.Grep,
|
|
3402
|
-
description: `Search file contents with ripgrep. mode=content (default) returns matching lines with paths and line numbers, mode=files returns only matching file paths, mode=count returns per-file match counts. Respects .gitignore and skips generated dirs unless include_ignored=true. Capped at ${DEFAULT_LIMIT2} matches by default; truncated results say how to continue and where the full output was saved.`,
|
|
4349
|
+
description: `Search file contents with ripgrep. mode=content (default) returns matching lines with paths and line numbers, mode=files returns only matching file paths, mode=count returns per-file match counts. Respects .gitignore and skips generated dirs unless include_ignored=true. Without rg, the async fallback uses GENERATED_DIRS only and does not apply .gitignore; unreadable, binary, oversized files and symlinks are reported as skipped. Capped at ${DEFAULT_LIMIT2} matches by default; truncated results say how to continue and where the full output was saved.`,
|
|
3403
4350
|
parameters: typebox_exports.Object({
|
|
3404
4351
|
pattern: typebox_exports.String({ description: "Search pattern (regex by default)." }),
|
|
3405
4352
|
path: typebox_exports.Optional(typebox_exports.String({ description: "Directory or file to search." })),
|
|
@@ -3425,8 +4372,8 @@ var grepTool = {
|
|
|
3425
4372
|
const context = parseContext(args.context);
|
|
3426
4373
|
if (context === null) return { kind: "error", message: "grep: context must be a non-negative number" };
|
|
3427
4374
|
const searchPath = resolveReadPath(typeof args.path === "string" && args.path.length > 0 ? args.path : ".");
|
|
3428
|
-
const
|
|
3429
|
-
if (!
|
|
4375
|
+
const stat6 = statIsDirectory(searchPath);
|
|
4376
|
+
if (!stat6.ok) return { kind: "error", message: `grep: ${stat6.message}` };
|
|
3430
4377
|
const limit = typeof args.limit === "number" && args.limit > 0 ? Math.floor(args.limit) : DEFAULT_LIMIT2;
|
|
3431
4378
|
const glob = typeof args.glob === "string" && args.glob.length > 0 ? args.glob : void 0;
|
|
3432
4379
|
const ignoreCase = args.ignore_case === true;
|
|
@@ -3448,7 +4395,7 @@ var grepTool = {
|
|
|
3448
4395
|
mode,
|
|
3449
4396
|
pattern,
|
|
3450
4397
|
searchPath,
|
|
3451
|
-
isDirectory:
|
|
4398
|
+
isDirectory: stat6.isDirectory,
|
|
3452
4399
|
...glob !== void 0 ? { glob } : {},
|
|
3453
4400
|
ignoreCase,
|
|
3454
4401
|
literal,
|
|
@@ -3462,7 +4409,7 @@ var grepTool = {
|
|
|
3462
4409
|
try {
|
|
3463
4410
|
const rgPath = resolveRgBinary();
|
|
3464
4411
|
if (rgPath) return await runRipgrep({ rgPath, ...shared });
|
|
3465
|
-
return fallbackGrep(shared);
|
|
4412
|
+
return await fallbackGrep(shared);
|
|
3466
4413
|
} finally {
|
|
3467
4414
|
releaseObservation(reservation);
|
|
3468
4415
|
}
|
|
@@ -3675,15 +4622,62 @@ var limitationTool = {
|
|
|
3675
4622
|
|
|
3676
4623
|
// src/tools/ls.ts
|
|
3677
4624
|
init_esm_shims();
|
|
3678
|
-
import {
|
|
4625
|
+
import { lstat as lstat2, opendir, readlink as readlink2, stat as stat4 } from "node:fs/promises";
|
|
3679
4626
|
import path3 from "node:path";
|
|
4627
|
+
import { setImmediate as yieldToLoop2 } from "node:timers/promises";
|
|
3680
4628
|
var DEFAULT_LIMIT3 = 500;
|
|
3681
4629
|
function parseLimit(value) {
|
|
3682
|
-
return typeof value === "number" && value
|
|
3683
|
-
}
|
|
4630
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 1 ? Math.floor(value) : DEFAULT_LIMIT3;
|
|
4631
|
+
}
|
|
4632
|
+
var compareEntries = (a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()) || a.order - b.order;
|
|
4633
|
+
var BoundedListingSelection = class {
|
|
4634
|
+
constructor(limit) {
|
|
4635
|
+
this.limit = limit;
|
|
4636
|
+
}
|
|
4637
|
+
limit;
|
|
4638
|
+
entries = [];
|
|
4639
|
+
nextOrder = 0;
|
|
4640
|
+
get retained() {
|
|
4641
|
+
return this.entries.length;
|
|
4642
|
+
}
|
|
4643
|
+
entryAt(index) {
|
|
4644
|
+
const entry = this.entries[index];
|
|
4645
|
+
if (!entry) throw new Error("Invalid listing heap index");
|
|
4646
|
+
return entry;
|
|
4647
|
+
}
|
|
4648
|
+
add(name) {
|
|
4649
|
+
const entry = { name, order: this.nextOrder++ };
|
|
4650
|
+
if (this.entries.length < this.limit) {
|
|
4651
|
+
this.entries.push(entry);
|
|
4652
|
+
let i2 = this.entries.length - 1;
|
|
4653
|
+
while (i2 > 0) {
|
|
4654
|
+
const parent = Math.floor((i2 - 1) / 2);
|
|
4655
|
+
if (compareEntries(this.entryAt(parent), entry) >= 0) break;
|
|
4656
|
+
this.entries[i2] = this.entryAt(parent);
|
|
4657
|
+
i2 = parent;
|
|
4658
|
+
}
|
|
4659
|
+
this.entries[i2] = entry;
|
|
4660
|
+
return;
|
|
4661
|
+
}
|
|
4662
|
+
if (compareEntries(entry, this.entryAt(0)) >= 0) return;
|
|
4663
|
+
this.entries[0] = entry;
|
|
4664
|
+
let i = 0;
|
|
4665
|
+
while (2 * i + 1 < this.entries.length) {
|
|
4666
|
+
let child = 2 * i + 1;
|
|
4667
|
+
if (child + 1 < this.entries.length && compareEntries(this.entryAt(child + 1), this.entryAt(child)) > 0) child++;
|
|
4668
|
+
if (compareEntries(entry, this.entryAt(child)) >= 0) break;
|
|
4669
|
+
this.entries[i] = this.entryAt(child);
|
|
4670
|
+
i = child;
|
|
4671
|
+
}
|
|
4672
|
+
this.entries[i] = entry;
|
|
4673
|
+
}
|
|
4674
|
+
sorted() {
|
|
4675
|
+
return [...this.entries].sort(compareEntries).map((entry) => entry.name);
|
|
4676
|
+
}
|
|
4677
|
+
};
|
|
3684
4678
|
var lsTool = {
|
|
3685
4679
|
name: ToolNames.Ls,
|
|
3686
|
-
description: 'List directory entries sorted alphabetically, "/" suffix for directories, dotfiles included.',
|
|
4680
|
+
description: 'List directory entries sorted alphabetically, "/" suffix for directories, dotfiles included. Symlinks render as name@ -> target, broken links as name@ (broken), and inaccessible entries are marked and counted.',
|
|
3687
4681
|
parameters: typebox_exports.Object({
|
|
3688
4682
|
path: typebox_exports.Optional(typebox_exports.String({ description: "Directory to list." })),
|
|
3689
4683
|
limit: typebox_exports.Optional(typebox_exports.Number({ description: `Max entries (default ${DEFAULT_LIMIT3}).` }))
|
|
@@ -3695,7 +4689,7 @@ var lsTool = {
|
|
|
3695
4689
|
const root = resolveReadPath(rootArg);
|
|
3696
4690
|
const limit = parseLimit(args.limit);
|
|
3697
4691
|
try {
|
|
3698
|
-
const rootStat =
|
|
4692
|
+
const rootStat = await stat4(root);
|
|
3699
4693
|
if (!rootStat.isDirectory()) {
|
|
3700
4694
|
return { kind: "error", message: `ls: not a directory: ${root}` };
|
|
3701
4695
|
}
|
|
@@ -3713,28 +4707,57 @@ var lsTool = {
|
|
|
3713
4707
|
hint: "Use find with a narrower pattern or continue in a follow-up turn."
|
|
3714
4708
|
});
|
|
3715
4709
|
}
|
|
4710
|
+
commitObservationReservation(reservation);
|
|
3716
4711
|
try {
|
|
3717
|
-
const
|
|
3718
|
-
const
|
|
4712
|
+
const policy = options?.allowsObservationPath ? void 0 : createSafetyPolicyEngine({ cwd: process.cwd() });
|
|
4713
|
+
const allows = options?.allowsObservationPath ?? ((entryPath) => policy?.evaluate({ tool: "read", args: { path: entryPath } }).reasonCode !== "path-policy:zeroAccessPaths");
|
|
4714
|
+
let withheldPaths = 0;
|
|
4715
|
+
let visibleCount = 0;
|
|
4716
|
+
let scanned = 0;
|
|
4717
|
+
const selection = new BoundedListingSelection(limit);
|
|
4718
|
+
for await (const entry of await opendir(root)) {
|
|
4719
|
+
if (++scanned % 128 === 0) await yieldToLoop2();
|
|
4720
|
+
if (options?.signal?.aborted) return { kind: "error", message: "ls: operation aborted during enumeration" };
|
|
4721
|
+
if (!allows(path3.join(root, entry.name))) {
|
|
4722
|
+
withheldPaths++;
|
|
4723
|
+
continue;
|
|
4724
|
+
}
|
|
4725
|
+
visibleCount++;
|
|
4726
|
+
selection.add(entry.name);
|
|
4727
|
+
}
|
|
4728
|
+
const entries = selection.sorted();
|
|
3719
4729
|
const outputEntries = [];
|
|
3720
|
-
|
|
4730
|
+
const entryLimitReached = visibleCount > limit;
|
|
4731
|
+
const search = newSearchCompleteness();
|
|
3721
4732
|
for (const entry of entries) {
|
|
3722
|
-
|
|
3723
|
-
entryLimitReached = true;
|
|
3724
|
-
break;
|
|
3725
|
-
}
|
|
4733
|
+
const entryPath = path3.join(root, entry);
|
|
3726
4734
|
try {
|
|
3727
|
-
const entryStat =
|
|
3728
|
-
|
|
4735
|
+
const entryStat = await lstat2(entryPath);
|
|
4736
|
+
if (entryStat.isSymbolicLink()) {
|
|
4737
|
+
const target = await readlink2(entryPath);
|
|
4738
|
+
try {
|
|
4739
|
+
await stat4(entryPath);
|
|
4740
|
+
outputEntries.push(`${entry}@ -> ${target}`);
|
|
4741
|
+
} catch (error) {
|
|
4742
|
+
const code = error.code;
|
|
4743
|
+
outputEntries.push(`${entry}@ (${code === "ENOENT" || code === "ENOTDIR" ? "broken" : "unreadable"})`);
|
|
4744
|
+
skipSearchPath(search, entryPath);
|
|
4745
|
+
}
|
|
4746
|
+
} else {
|
|
4747
|
+
outputEntries.push(entryStat.isDirectory() ? `${entry}/` : entry);
|
|
4748
|
+
}
|
|
3729
4749
|
} catch {
|
|
4750
|
+
outputEntries.push(`${entry} (unreadable)`);
|
|
4751
|
+
skipSearchPath(search, entryPath);
|
|
3730
4752
|
}
|
|
3731
4753
|
}
|
|
3732
4754
|
if (outputEntries.length === 0) {
|
|
3733
4755
|
return finalizeObservation({
|
|
3734
4756
|
tool: ToolNames.Ls,
|
|
3735
|
-
withheldPaths
|
|
4757
|
+
withheldPaths,
|
|
3736
4758
|
unit: "entries",
|
|
3737
4759
|
output: "(empty directory)",
|
|
4760
|
+
details: { skipped: search.skipped, selection: { scanned, retained: selection.retained } },
|
|
3738
4761
|
shownCount: 0,
|
|
3739
4762
|
totalCount: 0,
|
|
3740
4763
|
truncated: false,
|
|
@@ -3750,14 +4773,15 @@ var lsTool = {
|
|
|
3750
4773
|
const truncated = entryLimitReached || truncation.truncated;
|
|
3751
4774
|
return finalizeObservation({
|
|
3752
4775
|
tool: ToolNames.Ls,
|
|
3753
|
-
withheldPaths
|
|
4776
|
+
withheldPaths,
|
|
3754
4777
|
unit: "entries",
|
|
3755
4778
|
output: truncation.content,
|
|
4779
|
+
details: { skipped: search.skipped, selection: { scanned, retained: selection.retained } },
|
|
3756
4780
|
// Offload only when the byte cap cut collected entries; a bare
|
|
3757
4781
|
// entry limit continues via `next`.
|
|
3758
4782
|
...truncation.truncated ? { fullOutput } : {},
|
|
3759
4783
|
shownCount: truncation.outputLines,
|
|
3760
|
-
totalCount:
|
|
4784
|
+
totalCount: visibleCount,
|
|
3761
4785
|
truncated,
|
|
3762
4786
|
...entryLimitReached ? { next: `limit=${limit * 2}` } : {},
|
|
3763
4787
|
reservation,
|
|
@@ -3766,6 +4790,8 @@ var lsTool = {
|
|
|
3766
4790
|
} catch (err) {
|
|
3767
4791
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3768
4792
|
return { kind: "error", message: `ls: ${msg}` };
|
|
4793
|
+
} finally {
|
|
4794
|
+
releaseObservation(reservation);
|
|
3769
4795
|
}
|
|
3770
4796
|
}
|
|
3771
4797
|
};
|
|
@@ -3781,6 +4807,12 @@ var TOOL_PLANES = {
|
|
|
3781
4807
|
[ToolNames.CodeNav]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
3782
4808
|
[ToolNames.Context]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
3783
4809
|
[ToolNames.CredentialPresent]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
4810
|
+
// clio_docs and clio_library are the bundled-documentation and recipe-catalog
|
|
4811
|
+
// reads that used to be context scopes; same envelope, same read class.
|
|
4812
|
+
[ToolNames.ClioDocs]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
4813
|
+
[ToolNames.ClioLibrary]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
4814
|
+
// data streams structured files and never writes; parallel like read.
|
|
4815
|
+
[ToolNames.Data]: { plane: "observe", actionClass: "read", executionMode: "parallel" },
|
|
3784
4816
|
[ToolNames.Write]: { plane: "mutate", actionClass: "write", executionMode: "sequential" },
|
|
3785
4817
|
[ToolNames.Edit]: { plane: "mutate", actionClass: "write", executionMode: "sequential" },
|
|
3786
4818
|
[ToolNames.Bash]: { plane: "execute", actionClass: "execute", executionMode: "sequential" },
|
|
@@ -3788,6 +4820,9 @@ var TOOL_PLANES = {
|
|
|
3788
4820
|
// its containment posture, read class for its safety disposition.
|
|
3789
4821
|
[ToolNames.Git]: { plane: "execute", actionClass: "read", executionMode: "parallel" },
|
|
3790
4822
|
[ToolNames.Verify]: { plane: "execute", actionClass: "execute", executionMode: "sequential" },
|
|
4823
|
+
// run_script runs one interpreter over one workspace script and projects
|
|
4824
|
+
// itself to a bash command for the policy engine; execute class, sequential.
|
|
4825
|
+
[ToolNames.RunScript]: { plane: "execute", actionClass: "execute", executionMode: "sequential" },
|
|
3791
4826
|
[ToolNames.Dispatch]: { plane: "orchestrate", actionClass: "dispatch", executionMode: "sequential" },
|
|
3792
4827
|
// monitor never mutates a run, so it stays read class and parallel.
|
|
3793
4828
|
[ToolNames.Monitor]: { plane: "orchestrate", actionClass: "read", executionMode: "parallel" },
|
|
@@ -3814,9 +4849,17 @@ var TOOL_PLANES = {
|
|
|
3814
4849
|
// nothing else. Read class so it never trips a safety gate; sequential so
|
|
3815
4850
|
// two decisions in one batch never race the supersede lookup.
|
|
3816
4851
|
[ToolNames.Decide]: { plane: "orchestrate", actionClass: "read", executionMode: "sequential" },
|
|
4852
|
+
// web_read is the GET-only half of the split: no method, headers, or body,
|
|
4853
|
+
// so it is never an outward action.
|
|
4854
|
+
[ToolNames.WebRead]: { plane: "retrieve", actionClass: "read", executionMode: "parallel" },
|
|
3817
4855
|
[ToolNames.WebFetch]: { plane: "retrieve", actionClass: "read", executionMode: "parallel" },
|
|
3818
4856
|
[ToolNames.AskUser]: { plane: "interact", actionClass: "read", executionMode: "sequential" },
|
|
3819
|
-
[ToolNames.Artifact]: { plane: "artifact", actionClass: "write", executionMode: "sequential" }
|
|
4857
|
+
[ToolNames.Artifact]: { plane: "artifact", actionClass: "write", executionMode: "sequential" },
|
|
4858
|
+
// gateway lists, describes, and calls secondary capabilities. Its own class
|
|
4859
|
+
// is read; a call carries the capability's class through the same admission.
|
|
4860
|
+
// Sequential because a call may park for approval or run a sequential
|
|
4861
|
+
// capability, and two such calls in one batch must not interleave.
|
|
4862
|
+
[ToolNames.Gateway]: { plane: "gateway", actionClass: "read", executionMode: "sequential" }
|
|
3820
4863
|
};
|
|
3821
4864
|
var OBSERVE_ENVELOPE_SELF_CAPS = [
|
|
3822
4865
|
[ToolNames.Read, () => readMaxBytes()],
|
|
@@ -3824,22 +4867,18 @@ var OBSERVE_ENVELOPE_SELF_CAPS = [
|
|
|
3824
4867
|
[ToolNames.Find, () => OBSERVE_SELF_CAPS.find],
|
|
3825
4868
|
[ToolNames.Ls, () => OBSERVE_SELF_CAPS.ls],
|
|
3826
4869
|
[ToolNames.CodeNav, () => OBSERVE_SELF_CAPS.codeNav],
|
|
3827
|
-
[
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
OBSERVE_SELF_CAPS.contextWorkspace,
|
|
3833
|
-
OBSERVE_SELF_CAPS.contextLibrary
|
|
3834
|
-
)
|
|
3835
|
-
]
|
|
4870
|
+
[ToolNames.Context, () => Math.max(OBSERVE_SELF_CAPS.contextSkills, OBSERVE_SELF_CAPS.contextWorkspace)],
|
|
4871
|
+
[ToolNames.ClioDocs, () => OBSERVE_SELF_CAPS.contextDocs],
|
|
4872
|
+
[ToolNames.ClioLibrary, () => OBSERVE_SELF_CAPS.contextLibrary],
|
|
4873
|
+
[ToolNames.Data, () => DATA_OBSERVATION_SELF_CAP_BYTES],
|
|
4874
|
+
[ToolNames.Gateway, () => GATEWAY_FIND_SELF_CAP_BYTES]
|
|
3836
4875
|
];
|
|
3837
4876
|
var SESSION_BOUND_TOOLS = /* @__PURE__ */ new Set([]);
|
|
3838
4877
|
var DISPATCH_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.Dispatch, ToolNames.Monitor, ToolNames.Steer]);
|
|
3839
4878
|
var INTERACTIVE_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.AskUser]);
|
|
3840
4879
|
var PANES_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.Panes]);
|
|
3841
4880
|
var LEDGER_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.Ledger]);
|
|
3842
|
-
var NETWORK_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.WebFetch]);
|
|
4881
|
+
var NETWORK_BOUND_TOOLS = /* @__PURE__ */ new Set([ToolNames.WebRead, ToolNames.WebFetch]);
|
|
3843
4882
|
function validateBuiltinToolPolicy(specs, options = {}) {
|
|
3844
4883
|
const errors = [];
|
|
3845
4884
|
const registered = /* @__PURE__ */ new Map();
|
|
@@ -4138,11 +5177,10 @@ function createTasksTool(deps) {
|
|
|
4138
5177
|
|
|
4139
5178
|
// src/tools/write.ts
|
|
4140
5179
|
init_esm_shims();
|
|
4141
|
-
import {
|
|
4142
|
-
import { dirname } from "node:path";
|
|
5180
|
+
import { open as open2, stat as stat5 } from "node:fs/promises";
|
|
4143
5181
|
var writeTool = {
|
|
4144
5182
|
name: ToolNames.Write,
|
|
4145
|
-
description: "Write a UTF-8 text file, creating parent directories and overwriting existing files. Use edit for surgical changes.",
|
|
5183
|
+
description: "Write a UTF-8 text file, creating parent directories and overwriting existing files. Publishes atomically through symlinks, preserving mode bits. In-process writes are serialized; external writers are not locked and the last rename wins. Use edit for surgical changes.",
|
|
4146
5184
|
parameters: typebox_exports.Object({
|
|
4147
5185
|
path: typebox_exports.String({ description: "File path (relative or absolute)." }),
|
|
4148
5186
|
content: typebox_exports.String({ description: "Full UTF-8 file contents." })
|
|
@@ -4156,30 +5194,56 @@ var writeTool = {
|
|
|
4156
5194
|
if (content === null) return { kind: "error", message: "write: missing content argument" };
|
|
4157
5195
|
const filePath = resolveToCwd(pathArg);
|
|
4158
5196
|
try {
|
|
4159
|
-
|
|
4160
|
-
|
|
4161
|
-
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
5197
|
+
const bytes = Buffer.byteLength(content, "utf8");
|
|
5198
|
+
const { file, diff, previousEndedWithNewline, skipDiff } = await withFileMutationQueue(filePath, async () => {
|
|
5199
|
+
const previous = await stat5(filePath).catch((error) => {
|
|
5200
|
+
if (error.code === "ENOENT") return null;
|
|
5201
|
+
throw error;
|
|
5202
|
+
});
|
|
5203
|
+
if (previous && !previous.isFile()) throw new Error("Refusing directory or non-file target");
|
|
5204
|
+
let skipDiff2 = Math.max(previous?.size ?? 0, bytes) > 1024 * 1024;
|
|
5205
|
+
let previousContent = "";
|
|
5206
|
+
if (previous && !skipDiff2) {
|
|
5207
|
+
const handle = await open2(filePath, "r");
|
|
5208
|
+
try {
|
|
5209
|
+
const buffer = Buffer.allocUnsafe(1024 * 1024 + 1);
|
|
5210
|
+
let total = 0;
|
|
5211
|
+
while (total < buffer.length) {
|
|
5212
|
+
const { bytesRead } = await handle.read(buffer, total, buffer.length - total, total);
|
|
5213
|
+
if (bytesRead === 0) break;
|
|
5214
|
+
total += bytesRead;
|
|
5215
|
+
}
|
|
5216
|
+
skipDiff2 = total > 1024 * 1024;
|
|
5217
|
+
if (!skipDiff2) previousContent = buffer.toString("utf8", 0, total);
|
|
5218
|
+
} finally {
|
|
5219
|
+
await handle.close();
|
|
5220
|
+
}
|
|
4168
5221
|
}
|
|
4169
|
-
|
|
4170
|
-
|
|
5222
|
+
const diff2 = skipDiff2 ? void 0 : generateDiffString(previousContent, content).diff;
|
|
5223
|
+
const file2 = await publishFileAtomically(filePath, content);
|
|
5224
|
+
return { file: file2, diff: diff2, previousEndedWithNewline: previousContent.endsWith("\n"), skipDiff: skipDiff2 };
|
|
4171
5225
|
});
|
|
4172
|
-
const bytes = Buffer.byteLength(content, "utf8");
|
|
4173
|
-
const diff = generateDiffString(previousContent, content).diff;
|
|
4174
5226
|
let output = `wrote ${bytes}B to ${pathArg}`;
|
|
5227
|
+
if (skipDiff) output += "\nnote: diff skipped because the previous or new file exceeds 1 MiB";
|
|
5228
|
+
if (file.durabilityWarning) output += `
|
|
5229
|
+
${file.durabilityWarning}`;
|
|
4175
5230
|
if (previousEndedWithNewline && !content.endsWith("\n")) {
|
|
4176
5231
|
output += `
|
|
4177
5232
|
note: ${pathArg} no longer ends with a newline; the previous content did`;
|
|
4178
5233
|
}
|
|
4179
|
-
return {
|
|
5234
|
+
return {
|
|
5235
|
+
kind: "ok",
|
|
5236
|
+
output,
|
|
5237
|
+
details: {
|
|
5238
|
+
file: { before: file.before, after: file.after },
|
|
5239
|
+
diff,
|
|
5240
|
+
paths: [filePath],
|
|
5241
|
+
observation: { shownBytes: bytes }
|
|
5242
|
+
}
|
|
5243
|
+
};
|
|
4180
5244
|
} catch (err) {
|
|
4181
5245
|
const msg = err instanceof Error ? err.message : String(err);
|
|
4182
|
-
return { kind: "error", message: `write: ${msg}` };
|
|
5246
|
+
return { kind: "error", message: `write: Nothing was published. ${msg}` };
|
|
4183
5247
|
}
|
|
4184
5248
|
}
|
|
4185
5249
|
};
|
|
@@ -4212,7 +5276,13 @@ function registerCoreTools(registry, deps = {}) {
|
|
|
4212
5276
|
if (includeNetworkTools) {
|
|
4213
5277
|
registry.register({
|
|
4214
5278
|
...builtin(
|
|
4215
|
-
lazyTool(
|
|
5279
|
+
lazyTool(webReadToolSurface, async () => (await import("./web-fetch-6BRRVQON.js")).webReadTool),
|
|
5280
|
+
{ path: "src/tools/web-fetch.ts", scope: "core" }
|
|
5281
|
+
)
|
|
5282
|
+
});
|
|
5283
|
+
registry.register({
|
|
5284
|
+
...builtin(
|
|
5285
|
+
lazyTool(webFetchToolSurface, async () => (await import("./web-fetch-6BRRVQON.js")).webFetchTool),
|
|
4216
5286
|
{ path: "src/tools/web-fetch.ts", scope: "core" }
|
|
4217
5287
|
)
|
|
4218
5288
|
});
|
|
@@ -4222,13 +5292,35 @@ function registerCoreTools(registry, deps = {}) {
|
|
|
4222
5292
|
});
|
|
4223
5293
|
registry.register({
|
|
4224
5294
|
...builtin(
|
|
4225
|
-
lazyTool(verifyToolSurface, async () => (await import("./verify-
|
|
5295
|
+
lazyTool(verifyToolSurface, async () => (await import("./verify-SUKUK6XM.js")).verifyTool),
|
|
4226
5296
|
{ path: "src/tools/verify/index.ts", scope: "core" }
|
|
4227
5297
|
)
|
|
4228
5298
|
});
|
|
5299
|
+
const getWorkspaceRoot = () => deps.session?.current()?.cwd ?? process.cwd();
|
|
5300
|
+
registry.register({
|
|
5301
|
+
...builtin(
|
|
5302
|
+
lazyTool({ ...runScriptToolSurface, name: ToolNames.RunScript }, async () => ({
|
|
5303
|
+
...(await import("./run-script-H2KUDIII.js")).createRunScriptTool({ getWorkspaceRoot }),
|
|
5304
|
+
name: ToolNames.RunScript
|
|
5305
|
+
})),
|
|
5306
|
+
{ path: "src/tools/run-script.ts", scope: "core" }
|
|
5307
|
+
)
|
|
5308
|
+
});
|
|
5309
|
+
registry.register({
|
|
5310
|
+
...builtin(
|
|
5311
|
+
lazyTool(
|
|
5312
|
+
{
|
|
5313
|
+
...dataToolSurface,
|
|
5314
|
+
prepareAdmissionArguments: (args) => prepareDataAdmissionArguments(args, getWorkspaceRoot())
|
|
5315
|
+
},
|
|
5316
|
+
async () => (await import("./data-tool-KMBWKKWR.js")).createDataTool({ getCwd: getWorkspaceRoot })
|
|
5317
|
+
),
|
|
5318
|
+
{ path: "src/tools/gateway/data-tool.ts", scope: "core" }
|
|
5319
|
+
)
|
|
5320
|
+
});
|
|
4229
5321
|
registry.register({
|
|
4230
5322
|
...builtin(
|
|
4231
|
-
lazyTool(codeNavToolSurface, async () => (await import("./code-nav-
|
|
5323
|
+
lazyTool(codeNavToolSurface, async () => (await import("./code-nav-7OVCTP2Z.js")).codeNavTool),
|
|
4232
5324
|
{ path: "src/tools/codewiki/code-nav.ts", scope: "core" }
|
|
4233
5325
|
)
|
|
4234
5326
|
});
|
|
@@ -4263,7 +5355,7 @@ function registerCoreTools(registry, deps = {}) {
|
|
|
4263
5355
|
registry.register({
|
|
4264
5356
|
...builtin(
|
|
4265
5357
|
lazyTool(contextToolSurface, async () => {
|
|
4266
|
-
const { createContextTool } = await import("./context-
|
|
5358
|
+
const { createContextTool } = await import("./context-72VQV7JX.js");
|
|
4267
5359
|
if (!session) return createContextTool(skillToolDeps);
|
|
4268
5360
|
const { probeWorkspace } = await import("./workspace-DZ7JADBG.js");
|
|
4269
5361
|
return createContextTool({
|
|
@@ -4297,6 +5389,31 @@ function registerCoreTools(registry, deps = {}) {
|
|
|
4297
5389
|
registry.register({
|
|
4298
5390
|
...builtin(createArtifactTool({ getCwd: skillToolDeps.getCwd }), { path: "src/tools/artifact.ts", scope: "core" })
|
|
4299
5391
|
});
|
|
5392
|
+
registry.register({
|
|
5393
|
+
...builtin(
|
|
5394
|
+
lazyTool(clioDocsToolSurface, async () => (await import("./clio-context-tools-FT672MNZ.js")).createClioDocsTool()),
|
|
5395
|
+
{ path: "src/tools/gateway/clio-context-tools.ts", scope: "core" }
|
|
5396
|
+
)
|
|
5397
|
+
});
|
|
5398
|
+
registry.register({
|
|
5399
|
+
...builtin(
|
|
5400
|
+
lazyTool(
|
|
5401
|
+
clioLibraryToolSurface,
|
|
5402
|
+
async () => (await import("./clio-context-tools-FT672MNZ.js")).createClioLibraryTool({
|
|
5403
|
+
getCwd: skillToolDeps.getCwd,
|
|
5404
|
+
...deps.skillMarketplace !== void 0 ? { skillMarketplace: deps.skillMarketplace } : {},
|
|
5405
|
+
...deps.getSkillLoaderOptions ? { getSkillLoaderOptions: deps.getSkillLoaderOptions } : {}
|
|
5406
|
+
})
|
|
5407
|
+
),
|
|
5408
|
+
{ path: "src/tools/gateway/clio-context-tools.ts", scope: "core" }
|
|
5409
|
+
)
|
|
5410
|
+
});
|
|
5411
|
+
registry.register({
|
|
5412
|
+
...builtin(createGatewayTool({ registry, ...deps.mcpCapabilities ? { mcp: deps.mcpCapabilities } : {} }), {
|
|
5413
|
+
path: "src/tools/gateway/index.ts",
|
|
5414
|
+
scope: "core"
|
|
5415
|
+
})
|
|
5416
|
+
});
|
|
4300
5417
|
const includeLedgerTools = deps.includeLedgerTools === true || deps.agentLedger !== void 0;
|
|
4301
5418
|
if (includeLedgerTools) {
|
|
4302
5419
|
registry.register({
|
|
@@ -4335,7 +5452,7 @@ init_esm_shims();
|
|
|
4335
5452
|
import path4 from "node:path";
|
|
4336
5453
|
var import_yaml = __toESM(require_dist(), 1);
|
|
4337
5454
|
var MAX_INPUT_BYTES = 64 * 1024;
|
|
4338
|
-
function
|
|
5455
|
+
function quoted2(value) {
|
|
4339
5456
|
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
4340
5457
|
}
|
|
4341
5458
|
function jsonInput(args) {
|
|
@@ -4374,6 +5491,9 @@ Harness extension ${extension.id}@${extension.version}; runs an installed comman
|
|
|
4374
5491
|
parameters: tool.inputSchema,
|
|
4375
5492
|
baseActionClass: "execute",
|
|
4376
5493
|
executionMode: "sequential",
|
|
5494
|
+
// Reached through gateway find/describe/call; the spec, its execute
|
|
5495
|
+
// class, and its bash projection are unchanged by the placement.
|
|
5496
|
+
placement: "gateway",
|
|
4377
5497
|
sourceInfo: { path: extension.manifestPath, scope: "domain", extension: extension.provenance },
|
|
4378
5498
|
metadata: {
|
|
4379
5499
|
objective: tool.description,
|
|
@@ -4388,7 +5508,7 @@ Harness extension ${extension.id}@${extension.version}; runs an installed comman
|
|
|
4388
5508
|
input = jsonInput(args);
|
|
4389
5509
|
} catch {
|
|
4390
5510
|
}
|
|
4391
|
-
return { tool: "bash", args: { command: [vector.file, ...vector.args, input].map(
|
|
5511
|
+
return { tool: "bash", args: { command: [vector.file, ...vector.args, input].map(quoted2).join(" "), cwd } };
|
|
4392
5512
|
},
|
|
4393
5513
|
async run(args, options) {
|
|
4394
5514
|
try {
|
|
@@ -4485,9 +5605,10 @@ export {
|
|
|
4485
5605
|
stripBom,
|
|
4486
5606
|
applyEditsToNormalizedContent,
|
|
4487
5607
|
generateDiffString,
|
|
5608
|
+
createMcpCapabilitySource,
|
|
4488
5609
|
lazyTool,
|
|
4489
5610
|
registerCoreTools,
|
|
4490
5611
|
assertRegisteredBuiltinTools,
|
|
4491
5612
|
registerHarnessExtensionTools
|
|
4492
5613
|
};
|
|
4493
|
-
//# sourceMappingURL=chunk-
|
|
5614
|
+
//# sourceMappingURL=chunk-ZF6CV4WZ.js.map
|