agentic-qe 3.15.16 → 3.15.17
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/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +78 -0
- package/assets/skills/skills-manifest.json +1 -1
- package/dist/cli/bundle.js +6 -6
- package/dist/cli/chunks/adapter-OMILP6KH.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-45NWEKVS.js → agent-booster-wasm-6BUOFQZA.js} +2 -2
- package/dist/cli/chunks/{agent-handler-LVHMYFEF.js → agent-handler-HPDK3JI3.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-YDWOJFEQ.js → agent-memory-branch-5QKUTWK5.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-OXH5CCOS.js +2 -0
- package/dist/cli/chunks/{arena-CZKHXDDS.js → arena-7OKPMNHD.js} +2 -2
- package/dist/cli/chunks/{arena-ELDZH3CZ.js → arena-HZ35LESR.js} +4 -4
- package/dist/cli/chunks/{audit-5MT4T47Z.js → audit-XI575SVK.js} +3 -3
- package/dist/cli/chunks/base-MAK2BLTG.js +2 -0
- package/dist/cli/chunks/{better-sqlite3-6TGYPC2B.js → better-sqlite3-YO5X7ZJS.js} +2 -2
- package/dist/cli/chunks/{brain-handler-HQWZFO52.js → brain-handler-GCQZFZGQ.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-WVILM4SO.js → branch-enumerator-N6G44UU2.js} +2 -2
- package/dist/cli/chunks/{browser-RX5ALU3H.js → browser-EVKPTLOI.js} +2 -2
- package/dist/cli/chunks/browser-workflow-IR3VF2TL.js +2 -0
- package/dist/cli/chunks/{chunk-F742SZAX.js → chunk-2EQK7B5L.js} +2 -2
- package/dist/cli/chunks/{chunk-5NNNEWLS.js → chunk-2PCEMDIX.js} +67 -65
- package/dist/cli/chunks/{chunk-FBDVGRSC.js → chunk-2UUZCQSD.js} +7 -7
- package/dist/cli/chunks/{chunk-AG2EWGXS.js → chunk-2YWYW7NU.js} +2 -2
- package/dist/cli/chunks/{chunk-4LQFBY5L.js → chunk-45223KK6.js} +3 -3
- package/dist/cli/chunks/chunk-4EJLHNER.js +12 -0
- package/dist/cli/chunks/{chunk-KQYJ4VQ5.js → chunk-4L6WX5KC.js} +1 -1
- package/dist/cli/chunks/{chunk-KVF4NXGQ.js → chunk-4NKZU2JZ.js} +2 -2
- package/dist/cli/chunks/{chunk-YRAX7SFJ.js → chunk-4UKTIQDT.js} +2 -2
- package/dist/cli/chunks/{chunk-YTHTQPWR.js → chunk-4YM45Z5B.js} +1 -1
- package/dist/cli/chunks/{chunk-XIIQ5QTT.js → chunk-5FSPELOG.js} +2 -2
- package/dist/cli/chunks/{chunk-LKTTUHLF.js → chunk-5WATBVU6.js} +2 -2
- package/dist/cli/chunks/{chunk-SR52XP5F.js → chunk-5WYZVSL2.js} +1 -1
- package/dist/cli/chunks/{chunk-GQ6TUIKY.js → chunk-6LSZCEW2.js} +1 -1
- package/dist/cli/chunks/{chunk-NDJ7P2EP.js → chunk-6V6BD6PH.js} +1 -1
- package/dist/cli/chunks/{chunk-63GMRQ25.js → chunk-74MDUIAZ.js} +1 -1
- package/dist/cli/chunks/{chunk-4D4DENG6.js → chunk-776K4ZLE.js} +2 -2
- package/dist/cli/chunks/{chunk-ZJH5MU2I.js → chunk-7BSOO3CY.js} +2 -2
- package/dist/cli/chunks/{chunk-IOQ6ZQ5W.js → chunk-7SNSI4VY.js} +1 -1
- package/dist/cli/chunks/{chunk-LRSX2FJM.js → chunk-A4BVDYIL.js} +1 -1
- package/dist/cli/chunks/{chunk-SASBO5Y5.js → chunk-AGCS5GSO.js} +2 -2
- package/dist/cli/chunks/{chunk-GAHNO6JJ.js → chunk-AVHYJ3XP.js} +2 -2
- package/dist/cli/chunks/{chunk-CGGUM2YJ.js → chunk-BE7ZHM34.js} +2 -2
- package/dist/cli/chunks/{chunk-7TE5ONQQ.js → chunk-BHQ2DLJU.js} +1 -1
- package/dist/cli/chunks/{chunk-IESR7TNB.js → chunk-BKHEQIRZ.js} +2 -2
- package/dist/cli/chunks/{chunk-J4ELZNLY.js → chunk-BSIWI4ES.js} +2 -2
- package/dist/cli/chunks/{chunk-NVEWF4JV.js → chunk-C7QLLMYI.js} +1 -1
- package/dist/cli/chunks/{chunk-V5NHZV7S.js → chunk-CMN7PU2H.js} +2 -2
- package/dist/cli/chunks/{chunk-PPUZWYUG.js → chunk-COTQ44YO.js} +2 -2
- package/dist/cli/chunks/{chunk-5V3TI2LG.js → chunk-CQER6IJ5.js} +1 -1
- package/dist/cli/chunks/{chunk-SI6DPU5D.js → chunk-CVPXHDQU.js} +1 -1
- package/dist/cli/chunks/{chunk-6ZBXSOX6.js → chunk-CVYPMGUM.js} +2 -2
- package/dist/cli/chunks/{chunk-DXD6K2ZP.js → chunk-CXCMATZ6.js} +2 -2
- package/dist/cli/chunks/{chunk-PF7RBAYL.js → chunk-D75GLKEL.js} +2 -2
- package/dist/cli/chunks/chunk-DCDSN67A.js +2 -0
- package/dist/cli/chunks/{chunk-MAFQV4U4.js → chunk-DHKSPOUQ.js} +2 -2
- package/dist/cli/chunks/{chunk-RJIEG3NA.js → chunk-DJDVD6RM.js} +2 -2
- package/dist/cli/chunks/{chunk-GFWHUQSF.js → chunk-DNVRTJKB.js} +2 -2
- package/dist/cli/chunks/{chunk-G5RHFBAY.js → chunk-DS5IFRY6.js} +2 -2
- package/dist/cli/chunks/{chunk-BEKDKVQT.js → chunk-E7XIMOKW.js} +2 -2
- package/dist/cli/chunks/{chunk-5JZRZI4S.js → chunk-ECKHDHR2.js} +2 -2
- package/dist/cli/chunks/chunk-EPVPXHL7.js +2 -0
- package/dist/cli/chunks/{chunk-HVRRLYX6.js → chunk-ERYADKMZ.js} +2 -2
- package/dist/cli/chunks/{chunk-SUDMM5SO.js → chunk-EUWG2JG4.js} +2 -2
- package/dist/cli/chunks/{chunk-VSIKHWZ4.js → chunk-FAQ24UHB.js} +3 -3
- package/dist/cli/chunks/{chunk-YNMJEDN5.js → chunk-FBBPRVNF.js} +2 -2
- package/dist/cli/chunks/{chunk-72XSEQMW.js → chunk-FBSBXCZS.js} +2 -2
- package/dist/cli/chunks/{chunk-J7I6PABJ.js → chunk-G2X3OLMN.js} +2 -2
- package/dist/cli/chunks/{chunk-YU2BDRSD.js → chunk-GG7PMTHD.js} +1 -1
- package/dist/cli/chunks/{chunk-HLUXXCHF.js → chunk-GN6OE3JT.js} +1 -1
- package/dist/cli/chunks/{chunk-AGRV5B3T.js → chunk-GPPTRKEM.js} +2 -2
- package/dist/cli/chunks/{chunk-ZQ2XW3IP.js → chunk-H2LHWZRE.js} +2 -2
- package/dist/cli/chunks/{chunk-6DPYNAOK.js → chunk-HAQJFUAQ.js} +2 -2
- package/dist/cli/chunks/{chunk-SSUAAX3F.js → chunk-HD6W6PHV.js} +2 -2
- package/dist/cli/chunks/{chunk-L2DWPVNJ.js → chunk-HFZD5KLR.js} +1 -1
- package/dist/cli/chunks/{chunk-QVDCVD5D.js → chunk-HRUHHHVR.js} +2 -2
- package/dist/cli/chunks/{chunk-PINSJCM3.js → chunk-HVT7RMGV.js} +1 -1
- package/dist/cli/chunks/chunk-HWQPMUSN.js +2 -0
- package/dist/cli/chunks/{chunk-4NFQLP6R.js → chunk-HZ5O7G2P.js} +1 -1
- package/dist/cli/chunks/{chunk-C6D5AHBO.js → chunk-IHQGNDMX.js} +2 -2
- package/dist/cli/chunks/{chunk-QQWBWEJS.js → chunk-IJSROBM6.js} +3 -3
- package/dist/cli/chunks/{chunk-OCV2XEWQ.js → chunk-IJZFJPHS.js} +2 -2
- package/dist/cli/chunks/{chunk-N7HL5PHH.js → chunk-IKB3M7OF.js} +1 -1
- package/dist/cli/chunks/{chunk-24OX5TQJ.js → chunk-INI3Q4CN.js} +1 -1
- package/dist/cli/chunks/{chunk-SJ6Y4725.js → chunk-IOWEBPXJ.js} +2 -2
- package/dist/cli/chunks/{chunk-VXFLJNCA.js → chunk-IQL6XRF5.js} +2 -2
- package/dist/cli/chunks/{chunk-WP4RETKG.js → chunk-IRHXGCQR.js} +2 -2
- package/dist/cli/chunks/{chunk-63ZKI4PX.js → chunk-J3QFJI2Y.js} +2 -2
- package/dist/cli/chunks/{chunk-UHEOGZLX.js → chunk-J6QRNQJF.js} +5 -5
- package/dist/cli/chunks/{chunk-KNSRL6NO.js → chunk-J7Q5TXFZ.js} +2 -2
- package/dist/cli/chunks/{chunk-L6QSTQME.js → chunk-JHKKIJT2.js} +2 -2
- package/dist/cli/chunks/{chunk-VMDFFTCK.js → chunk-JI33PMPZ.js} +1 -1
- package/dist/cli/chunks/{chunk-E3D4GPLP.js → chunk-JRIJM4LE.js} +3 -3
- package/dist/cli/chunks/{chunk-XIQW7EFL.js → chunk-JVWZAE2H.js} +2 -2
- package/dist/cli/chunks/{chunk-YPBSUGMI.js → chunk-K7WAI662.js} +1 -1
- package/dist/cli/chunks/{chunk-RV74I3YO.js → chunk-KB34MTFZ.js} +2 -2
- package/dist/cli/chunks/{chunk-MI5MFHRA.js → chunk-KPIPVSIP.js} +2 -2
- package/dist/cli/chunks/{chunk-Y4PFUMOU.js → chunk-KR2TAAF6.js} +1 -1
- package/dist/cli/chunks/{chunk-W5HQUIML.js → chunk-KT2QCXO6.js} +2 -2
- package/dist/cli/chunks/{chunk-SSYAQZXA.js → chunk-KTORRIX3.js} +2 -2
- package/dist/cli/chunks/{chunk-CRPIYUTJ.js → chunk-LCWEQRZI.js} +2 -2
- package/dist/cli/chunks/{chunk-NO3IV5Q5.js → chunk-LG5PPJT7.js} +1 -1
- package/dist/cli/chunks/{chunk-5VZL4UVN.js → chunk-LIF6UWHV.js} +2 -2
- package/dist/cli/chunks/{chunk-32BPDLRZ.js → chunk-LN7NKE3N.js} +2 -2
- package/dist/cli/chunks/{chunk-ZB3LEFYG.js → chunk-LOLSZG5J.js} +2 -2
- package/dist/cli/chunks/{chunk-6XXZDV2C.js → chunk-LOMT4UC2.js} +2 -2
- package/dist/cli/chunks/{chunk-JDIYMZCQ.js → chunk-LRKLATSH.js} +2 -2
- package/dist/cli/chunks/{chunk-5SPCGMBB.js → chunk-LRY6UIRI.js} +2 -2
- package/dist/cli/chunks/{chunk-5PBLPQ5T.js → chunk-LV7UIK4Q.js} +2 -2
- package/dist/cli/chunks/{chunk-FDDC72IA.js → chunk-M2YI5YUR.js} +2 -2
- package/dist/cli/chunks/{chunk-D6COXLYE.js → chunk-MCXW3DKE.js} +2 -2
- package/dist/cli/chunks/{chunk-J442IZLE.js → chunk-MGZ6XZHU.js} +1 -1
- package/dist/cli/chunks/{chunk-TIUKLYAI.js → chunk-MLMD3I75.js} +1 -1
- package/dist/cli/chunks/{chunk-PHT5N7SC.js → chunk-MVVVGQJ6.js} +2 -2
- package/dist/cli/chunks/{chunk-525CFDUE.js → chunk-ND72UDVH.js} +2 -2
- package/dist/cli/chunks/{chunk-XWUWX7BV.js → chunk-NE3LRUNC.js} +4 -4
- package/dist/cli/chunks/{chunk-DTMAS2GB.js → chunk-NKUHMA4T.js} +2 -2
- package/dist/cli/chunks/{chunk-QPEOLAAS.js → chunk-NQFDJ6BT.js} +1 -1
- package/dist/cli/chunks/{chunk-MO55CVMT.js → chunk-NZJVDOUN.js} +14 -14
- package/dist/cli/chunks/{chunk-NZU4ACBZ.js → chunk-O7VJ3VKD.js} +2 -2
- package/dist/cli/chunks/{chunk-32GN3JKR.js → chunk-OJIUIEI4.js} +1 -1
- package/dist/cli/chunks/{chunk-UNGBRZDK.js → chunk-OO2M2QUV.js} +3 -3
- package/dist/cli/chunks/{chunk-CJSHWQXP.js → chunk-ORQ2YBRR.js} +2 -2
- package/dist/cli/chunks/chunk-OWIQR6N2.js +4 -0
- package/dist/cli/chunks/{chunk-NAEWCFQT.js → chunk-OWIZBZLN.js} +2 -2
- package/dist/cli/chunks/{chunk-24QHCVX6.js → chunk-P3D7SEHW.js} +1 -1
- package/dist/cli/chunks/{chunk-YLMNVLDK.js → chunk-P4OB6WDJ.js} +1 -1
- package/dist/cli/chunks/{chunk-PEQDY4BO.js → chunk-PCL5JRKN.js} +2 -2
- package/dist/cli/chunks/{chunk-IUBJVHNB.js → chunk-PIWGKGWP.js} +2 -2
- package/dist/cli/chunks/{chunk-GJYHWYXR.js → chunk-PK34KJH7.js} +2 -2
- package/dist/cli/chunks/{chunk-5B5QPCNU.js → chunk-POPSZDI2.js} +4 -4
- package/dist/cli/chunks/{chunk-HCH4Y6XX.js → chunk-Q6F3DYZN.js} +2 -2
- package/dist/cli/chunks/{chunk-SHKOCGNK.js → chunk-QJSSUBO3.js} +2 -2
- package/dist/cli/chunks/{chunk-DVYHMDFR.js → chunk-QN7HP2UW.js} +421 -418
- package/dist/cli/chunks/{chunk-ZFL436FN.js → chunk-QSQNXBD2.js} +2 -2
- package/dist/cli/chunks/{chunk-TVGI32MB.js → chunk-QTQDX4TZ.js} +3 -3
- package/dist/cli/chunks/{chunk-EK7OLYOZ.js → chunk-R3KBOQ3O.js} +2 -2
- package/dist/cli/chunks/{chunk-LE4QJREF.js → chunk-REY52O7J.js} +1 -1
- package/dist/cli/chunks/{chunk-LQLPB2T6.js → chunk-RKCN4B26.js} +2 -2
- package/dist/cli/chunks/{chunk-ZR2TKVXQ.js → chunk-S3DT5TPR.js} +2 -2
- package/dist/cli/chunks/{chunk-6ICX3FEG.js → chunk-S3TBOKAZ.js} +22 -22
- package/dist/cli/chunks/{chunk-JHQCRRJI.js → chunk-SAEECT23.js} +2 -2
- package/dist/cli/chunks/{chunk-VWPM27GU.js → chunk-SAZ4PJBR.js} +2 -2
- package/dist/cli/chunks/{chunk-KPRCB5LT.js → chunk-SFITYZLV.js} +2 -2
- package/dist/cli/chunks/{chunk-5LAVKGLH.js → chunk-SRBCBVSI.js} +2 -2
- package/dist/cli/chunks/{chunk-O5W3FIO6.js → chunk-SUAZ5Z47.js} +2 -2
- package/dist/cli/chunks/{chunk-KU2AUFGX.js → chunk-TDZ6N43D.js} +2 -2
- package/dist/cli/chunks/{chunk-YAPLJR7K.js → chunk-TIVKDIF7.js} +2 -2
- package/dist/cli/chunks/{chunk-U2A7NHZA.js → chunk-TM75GAXG.js} +2 -2
- package/dist/cli/chunks/{chunk-A5GBXCP5.js → chunk-TWBZONKT.js} +2 -2
- package/dist/cli/chunks/{chunk-I7MQIM2U.js → chunk-U4S74IIZ.js} +1 -1
- package/dist/cli/chunks/{chunk-3HD7E6HN.js → chunk-U5SMBJ6F.js} +2 -2
- package/dist/cli/chunks/{chunk-JQ3DYUMS.js → chunk-UHJVZEQA.js} +2 -2
- package/dist/cli/chunks/{chunk-C5FP5GW3.js → chunk-UOVCTK5L.js} +2 -2
- package/dist/cli/chunks/{chunk-HJ6ZGVTB.js → chunk-VDEKVIP5.js} +2 -2
- package/dist/cli/chunks/{chunk-KXCLACFG.js → chunk-VITV7AEC.js} +2 -2
- package/dist/cli/chunks/{chunk-P3EYRILV.js → chunk-VKREKVFI.js} +2 -2
- package/dist/cli/chunks/{chunk-2H4XH6FT.js → chunk-VLTDW7XJ.js} +2 -2
- package/dist/cli/chunks/{chunk-MD43XRX5.js → chunk-VQFV2IPV.js} +1 -1
- package/dist/cli/chunks/{chunk-67Z5R7RJ.js → chunk-VYPVU3JF.js} +2 -2
- package/dist/cli/chunks/{chunk-SDLWKRVL.js → chunk-WAOEQA3W.js} +2 -2
- package/dist/cli/chunks/{chunk-IOYG4VFL.js → chunk-WBDWHHKP.js} +2 -2
- package/dist/cli/chunks/{chunk-ASEOFRIG.js → chunk-WX4PO65Q.js} +2 -2
- package/dist/cli/chunks/chunk-X2DWHGCC.js +6 -0
- package/dist/cli/chunks/{chunk-CEYSYSK5.js → chunk-X5QD76IU.js} +2 -2
- package/dist/cli/chunks/{chunk-GSKMOPL7.js → chunk-XBTGEYED.js} +2 -2
- package/dist/cli/chunks/{chunk-FL64OUBA.js → chunk-XEMCHGAJ.js} +2 -2
- package/dist/cli/chunks/{chunk-2YZ4G6NW.js → chunk-XEYFZLIT.js} +1 -1
- package/dist/cli/chunks/{chunk-EA4YQVKS.js → chunk-XFTX3KLE.js} +1 -1
- package/dist/cli/chunks/{chunk-HGWXF45W.js → chunk-XPTCQKVE.js} +1 -1
- package/dist/cli/chunks/{chunk-CAKMOVZ6.js → chunk-YAJOBZE5.js} +2 -2
- package/dist/cli/chunks/{chunk-NQXXI77K.js → chunk-YCVLKU6H.js} +2 -2
- package/dist/cli/chunks/{chunk-AR67RJPY.js → chunk-YD2C6EPN.js} +2 -2
- package/dist/cli/chunks/{chunk-S75SOOZL.js → chunk-YKRLUTK7.js} +2 -2
- package/dist/cli/chunks/{chunk-IOKYCMTJ.js → chunk-YMUY3TES.js} +2 -2
- package/dist/cli/chunks/{chunk-5QO3R3TU.js → chunk-YR5QBUHZ.js} +2 -2
- package/dist/cli/chunks/{chunk-AJMJNQMP.js → chunk-Z7SKUC6P.js} +1 -1
- package/dist/cli/chunks/{chunk-KITOPKRG.js → chunk-ZAQMRFBB.js} +2 -2
- package/dist/cli/chunks/{chunk-AAMLQ2LF.js → chunk-ZC3KDNJW.js} +3 -3
- package/dist/cli/chunks/{chunk-VJCIEHEF.js → chunk-ZGV7L4MW.js} +1 -1
- package/dist/cli/chunks/{chunk-BY5OF7OH.js → chunk-ZN35XSKF.js} +2 -2
- package/dist/cli/chunks/{chunk-KKU2QGSJ.js → chunk-ZNXM6WVL.js} +2 -2
- package/dist/cli/chunks/{chunk-FLNAW7C4.js → chunk-ZP5AWQRO.js} +2 -2
- package/dist/cli/chunks/{chunk-IHRXZZQM.js → chunk-ZTP3DQ5M.js} +1 -1
- package/dist/cli/chunks/{chunk-OAEE6JWQ.js → chunk-ZVMSSCTH.js} +2 -2
- package/dist/cli/chunks/{chunk-M7WJCTG3.js → chunk-ZWUF27P4.js} +2 -2
- package/dist/cli/chunks/{ci-MFUR4CWV.js → ci-3RTTTS2D.js} +2 -2
- package/dist/cli/chunks/{ci-config-PNDLQ6XV.js → ci-config-XRUR3I4K.js} +2 -2
- package/dist/cli/chunks/{ci-output-PFZ4M7NC.js → ci-output-E5IAMU2U.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-5HH6NLZN.js → circuit-breaker-SHR2P44P.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-QCKYLGLC.js → claude-flow-setup-ZDDILFMF.js} +2 -2
- package/dist/cli/chunks/client-NO5FOWT4.js +2 -0
- package/dist/cli/chunks/{cline-installer-EASVPFXR.js → cline-installer-BGYVUM6G.js} +2 -2
- package/dist/cli/chunks/{code-UJXDVYRK.js → code-PJ4MC3MC.js} +3 -3
- package/dist/cli/chunks/{code-index-extractor-BZJ3UDP4.js → code-index-extractor-IW2P22YG.js} +2 -2
- package/dist/cli/chunks/{codex-installer-XSQZUVOZ.js → codex-installer-A7WZ6OGL.js} +2 -2
- package/dist/cli/chunks/{completions-OWOOJFI2.js → completions-KS23WD5J.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-KP5TOHDT.js → complexity-analyzer-Q7GLSR2E.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-IFKQXLHM.js → continuedev-installer-SK55BFW2.js} +2 -2
- package/dist/cli/chunks/copilot-installer-3N5J3WTM.js +3 -0
- package/dist/cli/chunks/core-handlers-JNAZPXE2.js +2 -0
- package/dist/cli/chunks/{cost-tracker-MMDDNKZB.js → cost-tracker-NENVSO4A.js} +2 -2
- package/dist/cli/chunks/{coverage-LUH2B7NT.js → coverage-5L7UQWDH.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-HEBM767Z.js +2 -0
- package/dist/cli/chunks/{cursor-installer-4YLM5GWM.js → cursor-installer-XXBO2ZE6.js} +2 -2
- package/dist/cli/chunks/{daemon-MZKVM4CJ.js → daemon-CDCQU3LR.js} +3 -3
- package/dist/cli/chunks/{daemon-CAVZ7OFV.js → daemon-JEBJGEUK.js} +4 -4
- package/dist/cli/chunks/{dag-attention-scheduler-X4CYW665.js → dag-attention-scheduler-HOMMF7FA.js} +2 -2
- package/dist/cli/chunks/{detect-7BM2XINO.js → detect-FXCOUG6X.js} +2 -2
- package/dist/cli/chunks/{dist-node-Y5APLEYB.js → dist-node-GXQ7FMTY.js} +2 -2
- package/dist/cli/chunks/{domain-handler-X3ZRJNAH.js → domain-handler-TI3JBAPC.js} +2 -2
- package/dist/cli/chunks/{domain-plugins-2UW5KQJB.js → domain-plugins-R7LTUM32.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-35W4CIBV.js → domain-transfer-LBIAFHIQ.js} +2 -2
- package/dist/cli/chunks/dream-GQDCEJMS.js +2 -0
- package/dist/cli/chunks/embed-and-insert-pattern-33KLHDD5.js +3 -0
- package/dist/cli/chunks/{embedding-space-SBM2MZD2.js → embedding-space-HHLWTBF5.js} +2 -2
- package/dist/cli/chunks/{eval-4QA2SROK.js → eval-KDOZMAXJ.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-Z6BF6KYM.js → experience-capture-middleware-X45PECQN.js} +3 -3
- package/dist/cli/chunks/{fast-paths-FIORX6GN.js → fast-paths-462V6UUB.js} +2 -2
- package/dist/cli/chunks/{feature-flags-ZOO7LMIC.js → feature-flags-G66OT3AS.js} +2 -2
- package/dist/cli/chunks/{feature-flags-6LYI2T4G.js → feature-flags-NIRQ4YDM.js} +2 -2
- package/dist/cli/chunks/file-discovery-33USPLB5.js +2 -0
- package/dist/cli/chunks/{fleet-7WF53H4F.js → fleet-PXWGB7CU.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-KJ6B7BRM.js → gnn-wrapper-7MUW3M5M.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-DEKKMOVW.js → heartbeat-handler-5237PB35.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-LIXLC5IH.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-62D5UH27.js +2 -0
- package/dist/cli/chunks/hnsw-index-GSGUMQQC.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-L27WS27N.js → hnsw-legacy-bridge-OSQPW7JP.js} +2 -2
- package/dist/cli/chunks/{hnswlib-node-4YOQC6L4.js → hnswlib-node-GX6WG2GB.js} +2 -2
- package/dist/cli/chunks/{hooks-TAOKV4EJ.js → hooks-GUWHL7VC.js} +10 -10
- package/dist/cli/chunks/hybrid-backend-FRWP4BOY.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-BODRJLHL.js → hypergraph-engine-SRWLLCU3.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-RKMYJNTU.js → hypergraph-handler-AVOPRHHO.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-7KF3AQXV.js +2 -0
- package/dist/cli/chunks/{init-guard-MXHSLSB2.js → init-guard-P4N6EVZS.js} +2 -2
- package/dist/cli/chunks/{init-handler-HUE57IFW.js → init-handler-LRGWOJMD.js} +6 -6
- package/dist/cli/chunks/init-wizard-XWWAXY25.js +2 -0
- package/dist/cli/chunks/kernel-ZEJPNDBW.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-S333IKYQ.js → kilocode-installer-7R2EPOQ6.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-WM5DLQWC.js → kiro-installer-QNM7DPOB.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-RRZQS7KY.js +2 -0
- package/dist/cli/chunks/{learning-LNHMQLH5.js → learning-7OIZBPXZ.js} +3 -3
- package/dist/cli/chunks/{llm-router-EWFXYZZR.js → llm-router-SIDXES23.js} +4 -4
- package/dist/cli/chunks/llm-router-service-3OSW67LC.js +2 -0
- package/dist/cli/chunks/{load-FGYGWVDK.js → load-EI2E2C3S.js} +2 -2
- package/dist/cli/chunks/load-test-7TRIH2WJ.js +2 -0
- package/dist/cli/chunks/{mcp-2FHNAAOM.js → mcp-IOE5WOCS.js} +2 -2
- package/dist/cli/chunks/{memory-DZMQ73AB.js → memory-DLYGJAP7.js} +5 -5
- package/dist/cli/chunks/memory-backend-G7ZW6Q2B.js +2 -0
- package/dist/cli/chunks/memory-handlers-TPF3KCO5.js +2 -0
- package/dist/cli/chunks/{multi-model-executor-6F2UAEUW.js → multi-model-executor-WHH4YCHM.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-XY3BGOTZ.js → opencode-installer-63FDZAMS.js} +2 -2
- package/dist/cli/chunks/{orchestrator-B4CNKUOS.js → orchestrator-3LA776KK.js} +5 -5
- package/dist/cli/chunks/pattern-null-store-OU3ZC3NR.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-R4GUFNMD.js → pattern-usage-recorder-NW54QUGI.js} +2 -2
- package/dist/cli/chunks/{pipeline-FG5RKVRO.js → pipeline-P3TYX6J6.js} +2 -2
- package/dist/cli/chunks/{platform-3BT4KEVJ.js → platform-FNA2WLI6.js} +2 -2
- package/dist/cli/chunks/{plugin-WI4RIN7O.js → plugin-NJS7BC2S.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-7ECDNQFS.js → prime-radiant-advanced-wasm-NIAVL2OT.js} +2 -2
- package/dist/cli/chunks/project-root-GMOFJEKD.js +2 -0
- package/dist/cli/chunks/protocol-executor-AD345XRO.js +2 -0
- package/dist/cli/chunks/{protocol-handler-WNODKPGW.js → protocol-handler-JU5C4JHY.js} +2 -2
- package/dist/cli/chunks/{prove-5RHAEPYZ.js → prove-35VOSLYP.js} +2 -2
- package/dist/cli/chunks/qe-reasoning-bank-NLTP26RC.js +2 -0
- package/dist/cli/chunks/{quality-WPHR7BGQ.js → quality-ET74X7HN.js} +2 -2
- package/dist/cli/chunks/{quality-gate-4RKTEZMX.js → quality-gate-FEDQISNB.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-2TB4FWS6.js +2 -0
- package/dist/cli/chunks/real-embeddings-II6CXTCI.js +2 -0
- package/dist/cli/chunks/{ref-validation-TPAWHOHH.js → ref-validation-DTBPYCEB.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-7AVHFNDI.js → roocode-installer-LYQEMR4J.js} +2 -2
- package/dist/cli/chunks/router-PLM3MWME.js +2 -0
- package/dist/cli/chunks/routing-feedback-I7VOX2HU.js +2 -0
- package/dist/cli/chunks/{routing-handler-YKEDVJSH.js → routing-handler-DJOJFPII.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-JUAMM354.js → ruvector-commands-VXYGJDPW.js} +2 -2
- package/dist/cli/chunks/rvf-dual-writer-GQZHFWO2.js +2 -0
- package/dist/cli/chunks/rvf-migration-adapter-3TVKBCAM.js +2 -0
- package/dist/cli/chunks/rvf-migration-coordinator-XUHKLMT6.js +2 -0
- package/dist/cli/chunks/rvf-native-adapter-5GUTYOWS.js +2 -0
- package/dist/cli/chunks/{rvf-store-integrity-VJDUIRTX.js → rvf-store-integrity-GA2ZYOEG.js} +2 -2
- package/dist/cli/chunks/safe-db-RZPQGLGQ.js +2 -0
- package/dist/cli/chunks/schedule-G7JMQDUX.js +2 -0
- package/dist/cli/chunks/scheduler-4SEGPCKD.js +2 -0
- package/dist/cli/chunks/{security-ORDN3RD2.js → security-MM6YOECX.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-CF4BCIO7.js → shared-rvf-adapter-6AHPA3V5.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-C32UBR6D.js → shared-rvf-dual-writer-EYAVY2GZ.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-IVE4SQXR.js +2 -0
- package/dist/cli/chunks/{standalone-memory-OXRJYZXN.js → standalone-memory-A3PLB4CZ.js} +2 -2
- package/dist/cli/chunks/{status-handler-BCX5D4HY.js → status-handler-OSSFAP4Z.js} +2 -2
- package/dist/cli/chunks/{structural-health-LFG7RUU6.js → structural-health-PGY5XUNO.js} +2 -2
- package/dist/cli/chunks/{sync-YJEE2K2L.js → sync-CWEHYGNN.js} +2 -2
- package/dist/cli/chunks/sync-PM6D7EQF.js +2 -0
- package/dist/cli/chunks/{task-handler-6LXKPTXJ.js → task-handler-LHMQ75W4.js} +2 -2
- package/dist/cli/chunks/{task-handlers-CILP36I7.js → task-handlers-S2TX5FTR.js} +3 -3
- package/dist/cli/chunks/test-4EGZZ6NJ.js +34 -0
- package/dist/cli/chunks/test-runner-process-72YACW6M.js +2 -0
- package/dist/cli/chunks/{test-scheduling-ISI2O4Q5.js → test-scheduling-YJQHH3XE.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-VUELSBOS.js → token-bootstrap-DJNETMVW.js} +2 -2
- package/dist/cli/chunks/{token-usage-XOC5KG7S.js → token-usage-WPNOJR6H.js} +2 -2
- package/dist/cli/chunks/{transformers-LSLQAARK.js → transformers-4MRPXCPU.js} +2 -2
- package/dist/cli/chunks/tree-sitter-wasm-parser-UVWSDXFR.js +2 -0
- package/dist/cli/chunks/{types-5BLCGLCR.js → types-6P5FB4EB.js} +2 -2
- package/dist/cli/chunks/unified-memory-2VMGSGQL.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-3KULVD3N.js +2 -0
- package/dist/cli/chunks/unified-persistence-QCSLU2SV.js +2 -0
- package/dist/cli/chunks/{upgrade-RQJYLK3J.js → upgrade-4ICTN63Y.js} +2 -2
- package/dist/cli/chunks/{validate-QBHWXXCK.js → validate-HQF5GZ7L.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-IKXBKFB5.js → validate-swarm-45JYG7VW.js} +2 -2
- package/dist/cli/chunks/visual-security-ZYP2KPH7.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-ZF6FIE5R.js → web-tree-sitter-UOTWZLNH.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-HQGDZT5D.js → windsurf-installer-WDWSBXGN.js} +2 -2
- package/dist/cli/chunks/witness-chain-5QRT7EMX.js +2 -0
- package/dist/cli/chunks/{witness-chain-DCHCAMSQ.js → witness-chain-DOYMNPC7.js} +2 -2
- package/dist/cli/chunks/{witness-chain-repair-PUX2NFDL.js → witness-chain-repair-CUF2AFQB.js} +2 -2
- package/dist/cli/chunks/{witness-chain-verifier-PX2OQ6XT.js → witness-chain-verifier-JB42X62J.js} +2 -2
- package/dist/cli/chunks/{witness-key-manager-RXYQNFJB.js → witness-key-manager-LXXO6L2G.js} +2 -2
- package/dist/cli/chunks/{workflow-FBKCA4H6.js → workflow-6ARK47NF.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-RYDDWIXN.js +2 -0
- package/dist/cli/chunks/{wrappers-TWSKBTWD.js → wrappers-CYQBOMPL.js} +2 -2
- package/dist/cli/commands/test.js +26 -4
- package/dist/coordination/handlers/test-execution-handlers.js +64 -20
- package/dist/domains/code-intelligence/services/semantic-analyzer.d.ts +8 -3
- package/dist/domains/code-intelligence/services/semantic-analyzer.js +39 -25
- package/dist/domains/code-intelligence/services/text-relevance.d.ts +32 -0
- package/dist/domains/code-intelligence/services/text-relevance.js +63 -0
- package/dist/domains/test-execution/coordinator.d.ts +3 -1
- package/dist/domains/test-execution/coordinator.js +13 -4
- package/dist/domains/test-execution/interfaces.d.ts +5 -0
- package/dist/domains/test-execution/plugin.js +2 -0
- package/dist/domains/test-execution/services/flaky-detector.d.ts +9 -1
- package/dist/domains/test-execution/services/flaky-detector.js +26 -8
- package/dist/domains/test-execution/services/retry-handler.d.ts +7 -1
- package/dist/domains/test-execution/services/retry-handler.js +44 -5
- package/dist/domains/test-execution/services/runner-test-cases.d.ts +2 -0
- package/dist/domains/test-execution/services/runner-test-cases.js +7 -3
- package/dist/domains/test-execution/services/test-executor.d.ts +5 -1
- package/dist/domains/test-execution/services/test-executor.js +79 -15
- package/dist/init/copilot-installer.d.ts +6 -0
- package/dist/init/copilot-installer.js +37 -17
- package/dist/init/platform-config-generator.d.ts +10 -0
- package/dist/init/platform-config-generator.js +26 -1
- package/dist/kernel/unified-memory.d.ts +8 -0
- package/dist/kernel/unified-memory.js +13 -0
- package/dist/learning/embedder-endpoint-client.d.ts +45 -0
- package/dist/learning/embedder-endpoint-client.js +98 -3
- package/dist/learning/embedding-space-registry.d.ts +75 -0
- package/dist/learning/embedding-space-registry.js +142 -0
- package/dist/learning/real-embeddings.d.ts +3 -0
- package/dist/learning/real-embeddings.js +49 -11
- package/dist/mcp/bundle.js +564 -555
- package/dist/mcp/protocol-server.js +1 -1
- package/dist/shared/embeddings/index.d.ts +2 -2
- package/dist/shared/embeddings/index.js +1 -1
- package/dist/shared/embeddings/nomic-embedder.d.ts +8 -2
- package/dist/shared/embeddings/nomic-embedder.js +19 -11
- package/dist/shared/embeddings/ollama-client.d.ts +28 -2
- package/dist/shared/embeddings/ollama-client.js +84 -22
- package/dist/shared/embeddings/types.d.ts +15 -0
- package/dist/shared/embeddings/types.js +4 -0
- package/dist/shared/pytest-junit-report.d.ts +93 -0
- package/dist/shared/pytest-junit-report.js +241 -0
- package/dist/shared/test-runner-project.d.ts +51 -1
- package/dist/shared/test-runner-project.js +140 -25
- package/package.json +1 -1
- package/dist/cli/chunks/adapter-6CQ2PIP5.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-73RR52VS.js +0 -2
- package/dist/cli/chunks/base-SMCMMVGP.js +0 -2
- package/dist/cli/chunks/browser-workflow-A2MEZ66K.js +0 -2
- package/dist/cli/chunks/chunk-EGYE5UPQ.js +0 -2
- package/dist/cli/chunks/chunk-KL7OKSU2.js +0 -4
- package/dist/cli/chunks/chunk-M4FRQ4TE.js +0 -12
- package/dist/cli/chunks/chunk-UE5ZOZR2.js +0 -2
- package/dist/cli/chunks/client-MHQRTZM4.js +0 -2
- package/dist/cli/chunks/copilot-installer-IGJ6KGQY.js +0 -3
- package/dist/cli/chunks/core-handlers-UAK3LLJE.js +0 -2
- package/dist/cli/chunks/cross-domain-router-WTRZQPNQ.js +0 -2
- package/dist/cli/chunks/dream-EJY24JN6.js +0 -2
- package/dist/cli/chunks/embed-and-insert-pattern-COG4C7ZI.js +0 -3
- package/dist/cli/chunks/file-discovery-UZSFSS4V.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-NVR356I7.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-LFMPLUJU.js +0 -2
- package/dist/cli/chunks/hnsw-index-POCPMVJH.js +0 -2
- package/dist/cli/chunks/hybrid-backend-4STAO7CV.js +0 -2
- package/dist/cli/chunks/impact-analyzer-3VIIISBQ.js +0 -2
- package/dist/cli/chunks/init-wizard-PL6QN6RQ.js +0 -2
- package/dist/cli/chunks/kernel-CCDWT7KS.js +0 -2
- package/dist/cli/chunks/knowledge-graph-KFOMEN3H.js +0 -2
- package/dist/cli/chunks/llm-router-service-7NBE2EX6.js +0 -2
- package/dist/cli/chunks/load-test-UNZUWY3F.js +0 -2
- package/dist/cli/chunks/memory-backend-DFGKWA2Q.js +0 -2
- package/dist/cli/chunks/memory-handlers-MP426XRJ.js +0 -2
- package/dist/cli/chunks/pattern-null-store-SSVF5TE5.js +0 -2
- package/dist/cli/chunks/project-root-BEANNYWU.js +0 -2
- package/dist/cli/chunks/protocol-executor-FQVIHXZ7.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-5TFYSE24.js +0 -2
- package/dist/cli/chunks/queen-coordinator-Y2OUL7IN.js +0 -2
- package/dist/cli/chunks/real-embeddings-OXLYU7JW.js +0 -2
- package/dist/cli/chunks/router-EP34O3KB.js +0 -2
- package/dist/cli/chunks/routing-feedback-FJCRKXNG.js +0 -2
- package/dist/cli/chunks/rvf-dual-writer-ILITJSFG.js +0 -2
- package/dist/cli/chunks/rvf-migration-adapter-XF6W4C2N.js +0 -2
- package/dist/cli/chunks/rvf-migration-coordinator-CMKG56AR.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-7YFW6S4Y.js +0 -2
- package/dist/cli/chunks/safe-db-TCAU4FUT.js +0 -2
- package/dist/cli/chunks/schedule-NB5KV435.js +0 -2
- package/dist/cli/chunks/scheduler-JKXGKVK6.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-IXCNZRTW.js +0 -2
- package/dist/cli/chunks/sync-OSF7C2NL.js +0 -2
- package/dist/cli/chunks/test-SD457QJ6.js +0 -34
- package/dist/cli/chunks/test-runner-process-VKD65QQU.js +0 -2
- package/dist/cli/chunks/tree-sitter-wasm-parser-YAIPHRIL.js +0 -2
- package/dist/cli/chunks/unified-memory-GI76TXFV.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-GXJ5BTZO.js +0 -2
- package/dist/cli/chunks/unified-persistence-OP7FDQPD.js +0 -2
- package/dist/cli/chunks/visual-security-GZ2MOKWB.js +0 -2
- package/dist/cli/chunks/witness-chain-P3XXXA62.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-P2APAJAA.js +0 -2
|
@@ -11,10 +11,11 @@ import { toError } from '../../shared/error-utils.js';
|
|
|
11
11
|
import { capDiagnostics, getTestRunnerExecutionError, TestRunnerExecutionError } from '../../shared/test-runner-verdict.js';
|
|
12
12
|
import { createVitestJsonReport } from '../../shared/vitest-json-report.js';
|
|
13
13
|
import { jestExactPathPattern, runnerFilePath } from '../../shared/test-runner-args.js';
|
|
14
|
-
import { testCasesFromRunnerReport } from '../../domains/test-execution/services/runner-test-cases.js';
|
|
14
|
+
import { testCaseFailureMessage, testCasesFromRunnerReport } from '../../domains/test-execution/services/runner-test-cases.js';
|
|
15
|
+
import { createPytestJunitReport, isPythonTestFile, pytestCommand, pytestRunFromReport, PYTEST_ENV } from '../../shared/pytest-junit-report.js';
|
|
15
16
|
import { runTestRunnerProcess } from '../../shared/test-runner-process.js';
|
|
16
17
|
import { MAX_PAYLOAD_FILE_BYTES, requirePayloadFiles } from '../../shared/io/payload-path-guard.js';
|
|
17
|
-
import { groupByRunnerProject, requireTestRunTargets } from '../../shared/test-runner-project.js';
|
|
18
|
+
import { groupByRunnerProject, requireTestRunTargets, runnerFrameworkFor } from '../../shared/test-runner-project.js';
|
|
18
19
|
function escapeRegExp(s) {
|
|
19
20
|
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
20
21
|
}
|
|
@@ -58,36 +59,76 @@ export function rewriteTempPathsInGeneratedTest(testCode, sourceFile, tempPath,
|
|
|
58
59
|
const newRef = sourceFile === tempPath ? (originalFilePath || sourceFile) : sourceFile;
|
|
59
60
|
return { testCode: newCode, sourceFile: newRef };
|
|
60
61
|
}
|
|
62
|
+
/** #1248: run Python test files with pytest, reading its JUnit report. */
|
|
63
|
+
async function runPytestTests(testFiles, cwd) {
|
|
64
|
+
const report = createPytestJunitReport();
|
|
65
|
+
try {
|
|
66
|
+
const { command, args } = pytestCommand(testFiles.map(file => runnerFilePath(file)), report.path);
|
|
67
|
+
const execution = await runTestRunnerProcess(command, args, { cwd, timeout: 120000, env: { ...process.env, ...PYTEST_ENV } });
|
|
68
|
+
const output = [execution.stderr, execution.stdout].filter(Boolean).join('\n');
|
|
69
|
+
if (execution.error || execution.signal) {
|
|
70
|
+
const reason = execution.error?.message ?? `Terminated by ${execution.signal}`;
|
|
71
|
+
return err(new TestRunnerExecutionError(`pytest could not complete: ${capDiagnostics(`${reason}\n${output}`)}`));
|
|
72
|
+
}
|
|
73
|
+
const run = pytestRunFromReport(report.read(), testFiles, execution.status, output, command);
|
|
74
|
+
if (!run.success)
|
|
75
|
+
return run;
|
|
76
|
+
const testCases = run.value.tests.map(test => {
|
|
77
|
+
const failureMessage = test.failureMessage && testCaseFailureMessage(test.failureMessage);
|
|
78
|
+
return {
|
|
79
|
+
name: test.name, file: test.file, status: test.status,
|
|
80
|
+
...(test.duration !== undefined ? { duration: test.duration } : {}),
|
|
81
|
+
...(failureMessage ? { failureMessage } : {}),
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
const { total, passed, failed, skipped } = run.value;
|
|
85
|
+
return ok({ total, passed, failed, skipped, testCases });
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
report.cleanup();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
61
91
|
/**
|
|
62
92
|
* Run `testFiles` (paths relative to the process cwd, or absolute) with the
|
|
63
93
|
* runner started in `cwd`.
|
|
64
94
|
*/
|
|
65
95
|
async function runProjectTests(testFiles, cwd) {
|
|
96
|
+
if (testFiles.some(isPythonTestFile))
|
|
97
|
+
return runPytestTests(testFiles, cwd);
|
|
66
98
|
// #1074: run the runner asynchronously so the MCP server keeps serving
|
|
67
99
|
// other requests (task_status, task_cancel, ...) during the test run.
|
|
68
100
|
const options = { cwd, timeout: 120000 };
|
|
101
|
+
const runJest = () => runTestRunnerProcess('npx', ['jest', ...testFiles.map(file => jestExactPathPattern(file)), '--json'], options);
|
|
69
102
|
let runner = 'vitest';
|
|
70
|
-
// Vitest 5 writes the JSON report to a file rather than stdout; an explicit
|
|
71
|
-
// --outputFile gives Vitest 4 and 5 the same contract.
|
|
72
|
-
const report = createVitestJsonReport();
|
|
73
103
|
let execution;
|
|
74
|
-
let output;
|
|
75
|
-
|
|
76
|
-
// #
|
|
77
|
-
execution = await runTestRunnerProcess('npx', ['vitest', 'run', ...testFiles.map(file => runnerFilePath(file)), '--reporter=json', ...report.args], options);
|
|
78
|
-
output = execution.error || execution.signal
|
|
79
|
-
? ''
|
|
80
|
-
: report.read(execution.stdout || '') ?? '';
|
|
81
|
-
}
|
|
82
|
-
finally {
|
|
83
|
-
report.cleanup();
|
|
84
|
-
}
|
|
85
|
-
// Preserve the existing Jest fallback when Vitest cannot produce a report.
|
|
86
|
-
if (!output.includes('{') && execution.status !== 0 && !execution.error && !execution.signal) {
|
|
104
|
+
let output = '';
|
|
105
|
+
if (runnerFrameworkFor(cwd) === 'jest') {
|
|
106
|
+
// #1272: a project configured for Jest runs with Jest, never Vitest first.
|
|
87
107
|
runner = 'jest';
|
|
88
|
-
execution = await
|
|
108
|
+
execution = await runJest();
|
|
89
109
|
output = execution.stdout || '';
|
|
90
110
|
}
|
|
111
|
+
else {
|
|
112
|
+
// Vitest 5 writes the JSON report to a file rather than stdout; an explicit
|
|
113
|
+
// --outputFile gives Vitest 4 and 5 the same contract.
|
|
114
|
+
const report = createVitestJsonReport();
|
|
115
|
+
try {
|
|
116
|
+
// #909: absolute paths cannot be read as flags (e.g. a "--watch" entry).
|
|
117
|
+
execution = await runTestRunnerProcess('npx', ['vitest', 'run', ...testFiles.map(file => runnerFilePath(file)), '--reporter=json', ...report.args], options);
|
|
118
|
+
output = execution.error || execution.signal
|
|
119
|
+
? ''
|
|
120
|
+
: report.read(execution.stdout || '') ?? '';
|
|
121
|
+
}
|
|
122
|
+
finally {
|
|
123
|
+
report.cleanup();
|
|
124
|
+
}
|
|
125
|
+
// Preserve the existing Jest fallback when Vitest cannot produce a report.
|
|
126
|
+
if (!output.includes('{') && execution.status !== 0 && !execution.error && !execution.signal) {
|
|
127
|
+
runner = 'jest';
|
|
128
|
+
execution = await runJest();
|
|
129
|
+
output = execution.stdout || '';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
91
132
|
const diagnostics = [execution.error?.message, execution.signal && `Terminated by ${execution.signal}`, execution.stderr, output].filter(Boolean).join('\n');
|
|
92
133
|
if (execution.error) {
|
|
93
134
|
return err(new TestRunnerExecutionError(`${runner} could not complete: ${capDiagnostics(diagnostics)}`));
|
|
@@ -286,8 +327,11 @@ export function registerTestExecutionHandlers(ctx) {
|
|
|
286
327
|
}
|
|
287
328
|
// #1247: a runner loads the config of the directory it starts in, so
|
|
288
329
|
// each runner project's files run from that project (or projectRoot).
|
|
330
|
+
// #1248: Python files run apart from the others, with pytest.
|
|
289
331
|
const groups = projectRoot
|
|
290
|
-
? [
|
|
332
|
+
? [testFiles.filter(isPythonTestFile), testFiles.filter(file => !isPythonTestFile(file))]
|
|
333
|
+
.filter(files => files.length > 0)
|
|
334
|
+
.map(files => ({ cwd: projectRoot, files }))
|
|
291
335
|
: groupByRunnerProject(testFiles);
|
|
292
336
|
const totals = { total: 0, passed: 0, failed: 0, skipped: 0 };
|
|
293
337
|
const testCases = [];
|
|
@@ -164,15 +164,20 @@ export declare class SemanticAnalyzerService implements ISemanticAnalyzerService
|
|
|
164
164
|
* vector, so vector search cannot rank them. Match those by text, label the
|
|
165
165
|
* hits 'lexical', and report the result as 'partial-vector' with the counts.
|
|
166
166
|
* Cosine and text-match scores are not comparable, so vector hits come
|
|
167
|
-
* first (by cosine), then lexical hits (by share of query words found
|
|
168
|
-
* reason says how many text matches the
|
|
167
|
+
* first (by cosine), then lexical hits (by share of query words found, ties
|
|
168
|
+
* by text relevance, #1287); the reason says how many text matches the
|
|
169
|
+
* limit left out.
|
|
169
170
|
*/
|
|
170
171
|
private withVectorlessFiles;
|
|
171
172
|
/** Word-overlap matching for a semantic query when no vectors can be used. */
|
|
172
173
|
private lexicalSearch;
|
|
173
174
|
private exactSearch;
|
|
174
175
|
private fuzzySearch;
|
|
175
|
-
/**
|
|
176
|
+
/**
|
|
177
|
+
* Token-overlap match of one indexed file, or null when it is filtered out or
|
|
178
|
+
* scores too low. The score is the share of query words found; `relevance`
|
|
179
|
+
* only orders equal scores (#1287).
|
|
180
|
+
*/
|
|
176
181
|
private fuzzyMatch;
|
|
177
182
|
private extractConcepts;
|
|
178
183
|
private detectPatterns;
|
|
@@ -6,12 +6,15 @@ import { createHash } from 'node:crypto';
|
|
|
6
6
|
import { ok, err } from '../../../shared/types/index.js';
|
|
7
7
|
import { NomicEmbedder, EMBEDDING_CONFIG, } from '../../../shared/embeddings/index.js';
|
|
8
8
|
import { toError } from '../../../shared/error-utils.js';
|
|
9
|
+
import { compareTextRelevance, textRelevance } from './text-relevance.js';
|
|
9
10
|
/**
|
|
10
11
|
* #1224: the message for a search over an empty index. "No results" is only
|
|
11
12
|
* reported after searching an index that holds code.
|
|
12
13
|
*/
|
|
13
14
|
export const NOTHING_INDEXED_FOR_SEARCH = 'No code is indexed for search yet, so the search was not run. ' +
|
|
14
15
|
'Index the project first (MCP code_index, or `aqe code index <path>`), then search again.';
|
|
16
|
+
/** Highest score first; equal scores by text relevance (#1287). */
|
|
17
|
+
const byScoreThenRelevance = (a, b) => b.hit.score - a.hit.score || compareTextRelevance(a.relevance, b.relevance);
|
|
15
18
|
/** Upper bound on indexed files one exact/fuzzy search reads. */
|
|
16
19
|
const MAX_INDEXED_FILES_SCANNED = 100_000;
|
|
17
20
|
const DEFAULT_CONFIG = {
|
|
@@ -60,17 +63,17 @@ export class SemanticAnalyzerService {
|
|
|
60
63
|
...this.config.nomicConfig,
|
|
61
64
|
enableFallback: false,
|
|
62
65
|
});
|
|
63
|
-
//
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
// #1229: Ollama lists the model under its own name (all-minilm:22m);
|
|
67
|
+
// the reason says whether Ollama is down or lacks the model.
|
|
68
|
+
const check = await nomicEmbedder.checkModel();
|
|
69
|
+
if (check.status === 'available') {
|
|
66
70
|
this.embedder = nomicEmbedder;
|
|
67
71
|
// Update dimension to match Nomic's output
|
|
68
72
|
this.config.embeddingDimension =
|
|
69
73
|
EMBEDDING_CONFIG.DIMENSIONS;
|
|
70
74
|
}
|
|
71
75
|
else {
|
|
72
|
-
this.embedderUnavailableReason =
|
|
73
|
-
`no embedding model available (Ollama model '${EMBEDDING_CONFIG.MODEL}' is not reachable)`;
|
|
76
|
+
this.embedderUnavailableReason = `no embedding model available (${check.reason})`;
|
|
74
77
|
}
|
|
75
78
|
}
|
|
76
79
|
else {
|
|
@@ -276,7 +279,7 @@ export class SemanticAnalyzerService {
|
|
|
276
279
|
}
|
|
277
280
|
/** Identifies the model behind stored vectors, so vectors from another model are not compared. */
|
|
278
281
|
embeddingModelId() {
|
|
279
|
-
return this.embedder instanceof NomicEmbedder ?
|
|
282
|
+
return this.embedder instanceof NomicEmbedder ? this.embedder.getModelId() : 'injected-provider';
|
|
280
283
|
}
|
|
281
284
|
isCurrentModelVector(metadata) {
|
|
282
285
|
return metadata.embeddingModel === this.embeddingModelId();
|
|
@@ -366,8 +369,9 @@ export class SemanticAnalyzerService {
|
|
|
366
369
|
* vector, so vector search cannot rank them. Match those by text, label the
|
|
367
370
|
* hits 'lexical', and report the result as 'partial-vector' with the counts.
|
|
368
371
|
* Cosine and text-match scores are not comparable, so vector hits come
|
|
369
|
-
* first (by cosine), then lexical hits (by share of query words found
|
|
370
|
-
* reason says how many text matches the
|
|
372
|
+
* first (by cosine), then lexical hits (by share of query words found, ties
|
|
373
|
+
* by text relevance, #1287); the reason says how many text matches the
|
|
374
|
+
* limit left out.
|
|
371
375
|
*/
|
|
372
376
|
async withVectorlessFiles(query, vectorHits, limit, scope, filters) {
|
|
373
377
|
const model = this.embeddingModelId();
|
|
@@ -383,16 +387,19 @@ export class SemanticAnalyzerService {
|
|
|
383
387
|
withoutVector++;
|
|
384
388
|
if (vectorFiles.has(stored.file))
|
|
385
389
|
return;
|
|
386
|
-
const
|
|
387
|
-
if (
|
|
388
|
-
lexicalHits.push({ ...hit, matchType: 'lexical' });
|
|
390
|
+
const match = this.fuzzyMatch(query, queryTokens, stored, scope, filters);
|
|
391
|
+
if (match)
|
|
392
|
+
lexicalHits.push({ ...match, hit: { ...match.hit, matchType: 'lexical' } });
|
|
389
393
|
});
|
|
390
394
|
const coverage = { indexedFiles, filesWithVector: indexedFiles - withoutVector };
|
|
391
395
|
if (withoutVector === 0) {
|
|
392
396
|
return { results: vectorHits, mode: 'vector', coverage };
|
|
393
397
|
}
|
|
394
398
|
const byScore = (a, b) => b.score - a.score;
|
|
395
|
-
const results = [
|
|
399
|
+
const results = [
|
|
400
|
+
...[...vectorHits].sort(byScore),
|
|
401
|
+
...lexicalHits.sort(byScoreThenRelevance).map((match) => match.hit),
|
|
402
|
+
].slice(0, limit);
|
|
396
403
|
const droppedLexical = vectorHits.length + lexicalHits.length - results.length;
|
|
397
404
|
return {
|
|
398
405
|
results,
|
|
@@ -449,18 +456,22 @@ export class SemanticAnalyzerService {
|
|
|
449
456
|
return results;
|
|
450
457
|
}
|
|
451
458
|
async fuzzySearch(query, limit, scope, filters) {
|
|
452
|
-
const
|
|
459
|
+
const matches = [];
|
|
453
460
|
const queryTokens = this.tokenize(query.toLowerCase());
|
|
454
461
|
await this.forEachIndexed((stored) => {
|
|
455
|
-
const
|
|
456
|
-
if (
|
|
457
|
-
|
|
462
|
+
const match = this.fuzzyMatch(query, queryTokens, stored, scope, filters);
|
|
463
|
+
if (match)
|
|
464
|
+
matches.push(match);
|
|
458
465
|
});
|
|
459
|
-
// Sort by score and limit
|
|
460
|
-
return
|
|
466
|
+
// Sort by score, ties by relevance (#1287), and limit
|
|
467
|
+
return matches.sort(byScoreThenRelevance).slice(0, limit).map((match) => match.hit);
|
|
461
468
|
}
|
|
462
|
-
/**
|
|
463
|
-
|
|
469
|
+
/**
|
|
470
|
+
* Token-overlap match of one indexed file, or null when it is filtered out or
|
|
471
|
+
* scores too low. The score is the share of query words found; `relevance`
|
|
472
|
+
* only orders equal scores (#1287).
|
|
473
|
+
*/
|
|
474
|
+
fuzzyMatch(query, queryTokens, stored, scope, filters) {
|
|
464
475
|
// Apply scope filter
|
|
465
476
|
if (scope && scope.length > 0 && !scope.some((s) => stored.file.includes(s))) {
|
|
466
477
|
return null;
|
|
@@ -475,11 +486,14 @@ export class SemanticAnalyzerService {
|
|
|
475
486
|
if (score < this.config.minScore)
|
|
476
487
|
return null;
|
|
477
488
|
return {
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
489
|
+
hit: {
|
|
490
|
+
file: stored.file,
|
|
491
|
+
snippet: this.extractSnippet(stored.content, 200),
|
|
492
|
+
score,
|
|
493
|
+
highlights: queryTokens.filter((t) => contentTokens.some((ct) => this.tokensMatch(t, ct))),
|
|
494
|
+
metadata: stored.metadata,
|
|
495
|
+
},
|
|
496
|
+
relevance: textRelevance(query, stored.content),
|
|
483
497
|
};
|
|
484
498
|
}
|
|
485
499
|
// ============================================================================
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic QE v3 - Text match relevance (#1287)
|
|
3
|
+
*
|
|
4
|
+
* Text matching scores a file by the share of query words it contains, so
|
|
5
|
+
* every file containing all of them scores 1.0. This ranks those ties by how
|
|
6
|
+
* well the file matches the query, without changing the score itself.
|
|
7
|
+
*/
|
|
8
|
+
/** How well one file's text matches a query. Higher fields rank first, in this order. */
|
|
9
|
+
export interface TextRelevance {
|
|
10
|
+
/**
|
|
11
|
+
* 2: an identifier is exactly the query words (`processOrder`, `process_order`
|
|
12
|
+
* for "process order"); 1: the query words appear next to each other
|
|
13
|
+
* (`process the order` does not, `process order` and `processOrderItems` do);
|
|
14
|
+
* 0: scattered, or the query is a single word.
|
|
15
|
+
*/
|
|
16
|
+
adjacency: number;
|
|
17
|
+
/** Share of query words found as a whole word (`order`), not only inside one (`orders`, `reorder`). */
|
|
18
|
+
exactWords: number;
|
|
19
|
+
/** Number of words in the file that contain a query word. */
|
|
20
|
+
occurrences: number;
|
|
21
|
+
}
|
|
22
|
+
/** Splits an identifier into lowercase words: `processOrder`, `process_order`, `PROCESS_ORDER` → process, order. */
|
|
23
|
+
export declare function identifierWords(identifier: string): string[];
|
|
24
|
+
/**
|
|
25
|
+
* Relevance of `content` to `query`. Words are compared case-insensitively,
|
|
26
|
+
* and identifiers are split into words, so the query `process order` matches
|
|
27
|
+
* the identifier `processOrder` as adjacent whole words.
|
|
28
|
+
*/
|
|
29
|
+
export declare function textRelevance(query: string, content: string): TextRelevance;
|
|
30
|
+
/** Sort comparator: more relevant first. */
|
|
31
|
+
export declare function compareTextRelevance(a: TextRelevance, b: TextRelevance): number;
|
|
32
|
+
//# sourceMappingURL=text-relevance.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic QE v3 - Text match relevance (#1287)
|
|
3
|
+
*
|
|
4
|
+
* Text matching scores a file by the share of query words it contains, so
|
|
5
|
+
* every file containing all of them scores 1.0. This ranks those ties by how
|
|
6
|
+
* well the file matches the query, without changing the score itself.
|
|
7
|
+
*/
|
|
8
|
+
/** Splits an identifier into lowercase words: `processOrder`, `process_order`, `PROCESS_ORDER` → process, order. */
|
|
9
|
+
export function identifierWords(identifier) {
|
|
10
|
+
return identifier
|
|
11
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
12
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')
|
|
13
|
+
.split(/[^A-Za-z0-9]+/)
|
|
14
|
+
.filter((word) => word.length > 0)
|
|
15
|
+
.map((word) => word.toLowerCase());
|
|
16
|
+
}
|
|
17
|
+
function identifiers(text) {
|
|
18
|
+
return text.split(/[^\w]+/).filter((token) => token.length > 0);
|
|
19
|
+
}
|
|
20
|
+
/** Whether `words` appears in `stream` as consecutive entries. */
|
|
21
|
+
function containsRun(stream, words) {
|
|
22
|
+
outer: for (let i = 0; i + words.length <= stream.length; i++) {
|
|
23
|
+
for (let j = 0; j < words.length; j++) {
|
|
24
|
+
if (stream[i + j] !== words[j])
|
|
25
|
+
continue outer;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Relevance of `content` to `query`. Words are compared case-insensitively,
|
|
33
|
+
* and identifiers are split into words, so the query `process order` matches
|
|
34
|
+
* the identifier `processOrder` as adjacent whole words.
|
|
35
|
+
*/
|
|
36
|
+
export function textRelevance(query, content) {
|
|
37
|
+
const queryWords = identifiers(query).flatMap(identifierWords);
|
|
38
|
+
const contentIdentifiers = identifiers(content);
|
|
39
|
+
const lowerIdentifiers = contentIdentifiers.map((token) => token.toLowerCase());
|
|
40
|
+
const splitIdentifiers = contentIdentifiers.map(identifierWords);
|
|
41
|
+
const contentWords = new Set([...lowerIdentifiers, ...splitIdentifiers.flat()]);
|
|
42
|
+
const queryTokens = identifiers(query.toLowerCase());
|
|
43
|
+
let adjacency = 0;
|
|
44
|
+
if (queryWords.length > 1) {
|
|
45
|
+
const phrase = queryWords.join(' ');
|
|
46
|
+
if (splitIdentifiers.some((words) => words.join(' ') === phrase))
|
|
47
|
+
adjacency = 2;
|
|
48
|
+
else if (containsRun(splitIdentifiers.flat(), queryWords))
|
|
49
|
+
adjacency = 1;
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
adjacency,
|
|
53
|
+
exactWords: queryWords.length === 0
|
|
54
|
+
? 0
|
|
55
|
+
: queryWords.filter((word) => contentWords.has(word)).length / queryWords.length,
|
|
56
|
+
occurrences: lowerIdentifiers.filter((token) => queryTokens.some((qt) => token.includes(qt))).length,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Sort comparator: more relevant first. */
|
|
60
|
+
export function compareTextRelevance(a, b) {
|
|
61
|
+
return b.adjacency - a.adjacency || b.exactWords - a.exactWords || b.occurrences - a.occurrences;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=text-relevance.js.map
|
|
@@ -131,7 +131,9 @@ export declare class TestExecutionCoordinator extends BaseDomainCoordinator<Test
|
|
|
131
131
|
*/
|
|
132
132
|
private retryFailures;
|
|
133
133
|
/**
|
|
134
|
-
*
|
|
134
|
+
* Fallback framework from file names. With no explicit framework, each
|
|
135
|
+
* runner project's own config still decides between jest and vitest (#1272),
|
|
136
|
+
* and Python files always run with pytest (#1248).
|
|
135
137
|
*/
|
|
136
138
|
private detectFramework;
|
|
137
139
|
/**
|
|
@@ -16,6 +16,7 @@ import { createDomainFinding, } from '../../coordination/consensus/domain-findin
|
|
|
16
16
|
// CQ-002: Base domain coordinator
|
|
17
17
|
import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
|
|
18
18
|
import { toError } from '../../shared/error-utils.js';
|
|
19
|
+
import { isPythonTestFile } from '../../shared/pytest-junit-report.js';
|
|
19
20
|
import { createMinCutTestOptimizer, } from './services/mincut-test-optimizer.js';
|
|
20
21
|
// ============================================================================
|
|
21
22
|
// Coordinator Configuration
|
|
@@ -146,6 +147,8 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
146
147
|
});
|
|
147
148
|
}
|
|
148
149
|
const framework = request.framework ?? this.detectFramework(testsToRun);
|
|
150
|
+
// #1272: without an explicit framework, each runner project's config decides.
|
|
151
|
+
const frameworkFromConfig = request.framework === undefined;
|
|
149
152
|
const workers = request.workers ?? Math.min(4, Math.max(1, testsToRun.length));
|
|
150
153
|
// Batched runners own internal parallelism, so the timeout applies to the
|
|
151
154
|
// whole discovered suite rather than one file.
|
|
@@ -157,6 +160,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
157
160
|
return this.executeParallel({
|
|
158
161
|
testFiles: testsToRun,
|
|
159
162
|
framework,
|
|
163
|
+
frameworkFromConfig,
|
|
160
164
|
workers,
|
|
161
165
|
timeout,
|
|
162
166
|
retryCount: request.retryCount,
|
|
@@ -167,6 +171,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
167
171
|
return this.execute({
|
|
168
172
|
testFiles: testsToRun,
|
|
169
173
|
framework,
|
|
174
|
+
frameworkFromConfig,
|
|
170
175
|
timeout,
|
|
171
176
|
retryCount: request.retryCount,
|
|
172
177
|
projectRoot: request.projectRoot,
|
|
@@ -198,9 +203,13 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
198
203
|
await this.executor.recordFinalOutcome(run, testFiles);
|
|
199
204
|
}
|
|
200
205
|
/**
|
|
201
|
-
*
|
|
206
|
+
* Fallback framework from file names. With no explicit framework, each
|
|
207
|
+
* runner project's own config still decides between jest and vitest (#1272),
|
|
208
|
+
* and Python files always run with pytest (#1248).
|
|
202
209
|
*/
|
|
203
210
|
detectFramework(testFiles) {
|
|
211
|
+
if (testFiles.every(isPythonTestFile))
|
|
212
|
+
return 'pytest';
|
|
204
213
|
// Check file patterns for common framework indicators
|
|
205
214
|
const hasVitestPattern = testFiles.some(f => f.includes('.test.') || f.includes('.spec.'));
|
|
206
215
|
const hasMochaPattern = testFiles.some(f => f.includes('_test.') || f.includes('.mocha.'));
|
|
@@ -209,7 +218,6 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
209
218
|
return 'vitest';
|
|
210
219
|
if (hasMochaPattern)
|
|
211
220
|
return 'mocha';
|
|
212
|
-
// Could add project config detection here (vitest.config.ts, jest.config.js, etc.)
|
|
213
221
|
return 'vitest';
|
|
214
222
|
}
|
|
215
223
|
/**
|
|
@@ -299,7 +307,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
299
307
|
if (this.config.infraHealing && result.value.failedTests.length > 0) {
|
|
300
308
|
this.feedInfraHealingFromFailures(result.value.failedTests);
|
|
301
309
|
// ADR-057: Attempt automatic recovery and re-run affected tests
|
|
302
|
-
const rerunResult = await this.attemptAutoRecoveryAndRerun(result.value.failedTests, request.framework, { timeout: request.timeout, env: request.env, retryCount: request.retryCount, projectRoot: request.projectRoot });
|
|
310
|
+
const rerunResult = await this.attemptAutoRecoveryAndRerun(result.value.failedTests, request.framework, { timeout: request.timeout, env: request.env, retryCount: request.retryCount, projectRoot: request.projectRoot, frameworkFromConfig: request.frameworkFromConfig });
|
|
303
311
|
if (rerunResult)
|
|
304
312
|
return rerunResult;
|
|
305
313
|
}
|
|
@@ -410,7 +418,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
410
418
|
if (this.config.infraHealing && result.value.failedTests.length > 0) {
|
|
411
419
|
this.feedInfraHealingFromFailures(result.value.failedTests);
|
|
412
420
|
// ADR-057: Attempt automatic recovery and re-run affected tests
|
|
413
|
-
const rerunResult = await this.attemptAutoRecoveryAndRerun(result.value.failedTests, request.framework, { timeout: request.timeout, env: request.env, retryCount: request.retryCount, projectRoot: request.projectRoot });
|
|
421
|
+
const rerunResult = await this.attemptAutoRecoveryAndRerun(result.value.failedTests, request.framework, { timeout: request.timeout, env: request.env, retryCount: request.retryCount, projectRoot: request.projectRoot, frameworkFromConfig: request.frameworkFromConfig });
|
|
414
422
|
if (rerunResult)
|
|
415
423
|
return rerunResult;
|
|
416
424
|
}
|
|
@@ -631,6 +639,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
631
639
|
return this.execute({
|
|
632
640
|
testFiles: [...filesToRerun],
|
|
633
641
|
framework,
|
|
642
|
+
frameworkFromConfig: originalRequest.frameworkFromConfig,
|
|
634
643
|
timeout: originalRequest.timeout,
|
|
635
644
|
env: originalRequest.env,
|
|
636
645
|
retryCount: originalRequest.retryCount,
|
|
@@ -56,6 +56,11 @@ export interface ISimpleTestRequest {
|
|
|
56
56
|
export interface IExecuteTestsRequest {
|
|
57
57
|
testFiles: string[];
|
|
58
58
|
framework: string;
|
|
59
|
+
/**
|
|
60
|
+
* #1272: the caller named no framework, so each runner project's own config
|
|
61
|
+
* chooses jest or vitest; `framework` is used where it names neither.
|
|
62
|
+
*/
|
|
63
|
+
frameworkFromConfig?: boolean;
|
|
59
64
|
timeout?: number;
|
|
60
65
|
env?: Record<string, string>;
|
|
61
66
|
reporters?: string[];
|
|
@@ -80,6 +80,8 @@ export class TestExecutionPlugin extends BaseDomainPlugin {
|
|
|
80
80
|
// Simple request format
|
|
81
81
|
const request = {
|
|
82
82
|
testFiles,
|
|
83
|
+
// #1272: an explicit framework wins over the project's config.
|
|
84
|
+
framework: typeof payload.framework === 'string' ? payload.framework : undefined,
|
|
83
85
|
parallel: payload.parallel,
|
|
84
86
|
retryCount: payload.retryCount,
|
|
85
87
|
timeout: payload.timeout,
|
|
@@ -39,7 +39,8 @@ export interface FlakyDetectorConfig {
|
|
|
39
39
|
*/
|
|
40
40
|
testRunnerArgs: string[];
|
|
41
41
|
/**
|
|
42
|
-
* Working directory for test execution.
|
|
42
|
+
* Working directory for test execution. When omitted, each file runs from
|
|
43
|
+
* its nearest runner project, as test_execute_parallel does (#1247, #1272).
|
|
43
44
|
*/
|
|
44
45
|
cwd?: string;
|
|
45
46
|
/**
|
|
@@ -112,6 +113,13 @@ export declare class FlakyDetectorService implements IFlakyTestDetector {
|
|
|
112
113
|
/** Cache TTL for analysis results (1 hour) */
|
|
113
114
|
private readonly ANALYSIS_CACHE_TTL_MS;
|
|
114
115
|
constructor(memory: MemoryBackend, config?: Partial<FlakyDetectorConfig>);
|
|
116
|
+
/** True when the caller chose the runner command; else the project's config picks it. */
|
|
117
|
+
private readonly runnerConfigured;
|
|
118
|
+
/**
|
|
119
|
+
* #1272: the runner command for a run started in `cwd`. A configured command
|
|
120
|
+
* is used as given; the default runs Jest in a project configured for Jest.
|
|
121
|
+
*/
|
|
122
|
+
private runnerCommandIn;
|
|
115
123
|
/**
|
|
116
124
|
* Detect flaky tests by running them multiple times
|
|
117
125
|
*/
|
|
@@ -14,6 +14,7 @@ import { safeJsonParse } from '../../../shared/safe-json.js';
|
|
|
14
14
|
import { getTestRunnerExecutionError } from '../../../shared/test-runner-verdict.js';
|
|
15
15
|
import { createVitestJsonReport, needsVitestJsonReportFile } from '../../../shared/vitest-json-report.js';
|
|
16
16
|
import { isJestCommand, jestExactPathPattern, runnerFilePath } from '../../../shared/test-runner-args.js';
|
|
17
|
+
import { runnerCwdFor, runnerFrameworkFor } from '../../../shared/test-runner-project.js';
|
|
17
18
|
import { secureRandom } from '../../../shared/utils/crypto-random.js';
|
|
18
19
|
import { redactFailureText } from './runner-test-cases.js';
|
|
19
20
|
const DEFAULT_FLAKY_CONFIG = {
|
|
@@ -41,6 +42,19 @@ export class FlakyDetectorService {
|
|
|
41
42
|
constructor(memory, config = {}) {
|
|
42
43
|
this.memory = memory;
|
|
43
44
|
this.config = { ...DEFAULT_FLAKY_CONFIG, ...config };
|
|
45
|
+
this.runnerConfigured = config.testRunner !== undefined || config.testRunnerArgs !== undefined;
|
|
46
|
+
}
|
|
47
|
+
/** True when the caller chose the runner command; else the project's config picks it. */
|
|
48
|
+
runnerConfigured;
|
|
49
|
+
/**
|
|
50
|
+
* #1272: the runner command for a run started in `cwd`. A configured command
|
|
51
|
+
* is used as given; the default runs Jest in a project configured for Jest.
|
|
52
|
+
*/
|
|
53
|
+
runnerCommandIn(cwd) {
|
|
54
|
+
if (!this.runnerConfigured && runnerFrameworkFor(cwd) === 'jest') {
|
|
55
|
+
return { runner: 'npx', runnerArgs: ['jest', '--json'] };
|
|
56
|
+
}
|
|
57
|
+
return { runner: this.config.testRunner, runnerArgs: this.config.testRunnerArgs };
|
|
44
58
|
}
|
|
45
59
|
/**
|
|
46
60
|
* Detect flaky tests by running them multiple times
|
|
@@ -259,20 +273,24 @@ export class FlakyDetectorService {
|
|
|
259
273
|
const runId = uuidv4();
|
|
260
274
|
const startTime = Date.now();
|
|
261
275
|
return new Promise((resolve, reject) => {
|
|
262
|
-
const
|
|
276
|
+
const fileBase = this.config.cwd ?? process.cwd();
|
|
277
|
+
// #1272: a runner loads the config of the directory it starts in, so the
|
|
278
|
+
// file runs from its own runner project (the file path stays absolute).
|
|
279
|
+
const cwd = this.config.cwd ?? runnerCwdFor(file);
|
|
280
|
+
const { runner, runnerArgs } = this.runnerCommandIn(cwd);
|
|
263
281
|
// #909: pass an absolute path (never read as a flag); Jest reads it as a
|
|
264
282
|
// regex, so escape and anchor it to select exactly this file.
|
|
265
|
-
const fileArg = isJestCommand([
|
|
266
|
-
? jestExactPathPattern(file,
|
|
267
|
-
: runnerFilePath(file,
|
|
268
|
-
const baseArgs = [...
|
|
283
|
+
const fileArg = isJestCommand([runner, ...runnerArgs])
|
|
284
|
+
? jestExactPathPattern(file, fileBase)
|
|
285
|
+
: runnerFilePath(file, fileBase);
|
|
286
|
+
const baseArgs = [...runnerArgs, fileArg];
|
|
269
287
|
// Vitest 5 writes --reporter=json output to a file, not stdout. Detect
|
|
270
288
|
// Vitest from the runner command too (testRunner: 'vitest', args: ['run', ...]).
|
|
271
|
-
const report = needsVitestJsonReportFile([
|
|
289
|
+
const report = needsVitestJsonReportFile([runner, ...baseArgs])
|
|
272
290
|
? createVitestJsonReport()
|
|
273
291
|
: undefined;
|
|
274
292
|
const args = report ? [...baseArgs, ...report.args] : baseArgs;
|
|
275
|
-
const child = spawn(
|
|
293
|
+
const child = spawn(runner, args, {
|
|
276
294
|
cwd,
|
|
277
295
|
env: { ...process.env, ...this.config.env },
|
|
278
296
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -295,7 +313,7 @@ export class FlakyDetectorService {
|
|
|
295
313
|
clearTimeout(timeout);
|
|
296
314
|
report?.cleanup();
|
|
297
315
|
reject(new Error(`Failed to execute test runner: ${error.message}. ` +
|
|
298
|
-
`Ensure ${
|
|
316
|
+
`Ensure ${[runner, ...runnerArgs.slice(0, 1)].join(' ')} is installed and accessible.`));
|
|
299
317
|
});
|
|
300
318
|
child.on('close', (code) => {
|
|
301
319
|
clearTimeout(timeout);
|
|
@@ -8,7 +8,7 @@ import { MemoryBackend } from '../../../kernel/interfaces';
|
|
|
8
8
|
/**
|
|
9
9
|
* Supported test runners for retry execution
|
|
10
10
|
*/
|
|
11
|
-
export type TestRunner = 'vitest' | 'jest' | 'mocha' | 'auto';
|
|
11
|
+
export type TestRunner = 'vitest' | 'jest' | 'mocha' | 'pytest' | 'auto';
|
|
12
12
|
/**
|
|
13
13
|
* Configuration for the retry handler service
|
|
14
14
|
*/
|
|
@@ -159,6 +159,12 @@ export declare class RetryHandlerService implements IRetryHandler {
|
|
|
159
159
|
* Spawn a test process and parse the result
|
|
160
160
|
*/
|
|
161
161
|
private spawnTestProcess;
|
|
162
|
+
/**
|
|
163
|
+
* #1248: a pytest retry passes only when its JUnit report shows the test
|
|
164
|
+
* passed. A node id pytest cannot find (exit code 4) or no collected test
|
|
165
|
+
* (exit code 5) reran nothing.
|
|
166
|
+
*/
|
|
167
|
+
private parsePytestRetry;
|
|
162
168
|
/**
|
|
163
169
|
* Parse test runner output to determine pass/fail status
|
|
164
170
|
*/
|