agentic-qe 3.13.4 → 3.13.6
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/helpers/.helpers-version +1 -1
- package/.claude/helpers/auto-memory-hook.mjs +430 -430
- package/.claude/helpers/helpers.manifest.json +6 -6
- package/.claude/helpers/hook-handler.cjs +565 -565
- package/.claude/helpers/intelligence.cjs +1058 -1058
- package/.claude/helpers/statusline.cjs +1022 -968
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +89 -0
- package/assets/skills/skills-manifest.json +1 -1
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-7XXMDGFO.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-PR3RQWXF.js → agent-booster-wasm-TMON22NL.js} +2 -2
- package/dist/cli/chunks/{agent-handler-J5EPFBSZ.js → agent-handler-JOX6O26U.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-CCHI6QAA.js → agent-memory-branch-AMIJIDCM.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-2KGMCBJG.js +2 -0
- package/dist/cli/chunks/{arena-KMKBGSMY.js → arena-N6SO2CCQ.js} +2 -2
- package/dist/cli/chunks/{arena-SI7IPVZ3.js → arena-RKLFXDMO.js} +4 -4
- package/dist/cli/chunks/{audit-ZDKR3HT6.js → audit-ZJE3DUH6.js} +3 -3
- package/dist/cli/chunks/base-4M3VL4XK.js +2 -0
- package/dist/cli/chunks/{hnswlib-node-BP5CZGMD.js → better-sqlite3-5G6AR6LX.js} +2 -2
- package/dist/cli/chunks/{brain-handler-MSYMTM5B.js → brain-handler-QD4DZ574.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-FRAHCBTO.js → branch-enumerator-PG3OUYE6.js} +2 -2
- package/dist/cli/chunks/{browser-4KHKVNYC.js → browser-Y2DJG7HQ.js} +2 -2
- package/dist/cli/chunks/browser-workflow-DHIPXEGO.js +2 -0
- package/dist/cli/chunks/{chunk-Q4VZXT6X.js → chunk-2BUDKFIE.js} +1 -1
- package/dist/cli/chunks/{chunk-NQVF4M7L.js → chunk-2FTAMEOB.js} +1 -1
- package/dist/cli/chunks/{chunk-AROPZPNG.js → chunk-2ILX73JG.js} +1 -1
- package/dist/cli/chunks/{chunk-6GNVVQW3.js → chunk-2SVDR5KB.js} +2 -2
- package/dist/cli/chunks/{chunk-HN2DD2DQ.js → chunk-2VUXU22M.js} +2 -2
- package/dist/cli/chunks/{chunk-U52IQFMP.js → chunk-3OUHOJBN.js} +1 -1
- package/dist/cli/chunks/{chunk-BQRCNRTJ.js → chunk-3QJH5W55.js} +2 -2
- package/dist/cli/chunks/{chunk-OU2YHXJY.js → chunk-3TC4ZPGR.js} +2 -2
- package/dist/cli/chunks/{chunk-ISGKDLZ7.js → chunk-463VBHHH.js} +2 -2
- package/dist/cli/chunks/{chunk-IN5KRJSE.js → chunk-4VWB64OH.js} +1 -1
- package/dist/cli/chunks/{chunk-WSQE3VZB.js → chunk-4YFBAXRD.js} +1 -1
- package/dist/cli/chunks/{chunk-N7LIYK7Z.js → chunk-523XPMTU.js} +1 -1
- package/dist/cli/chunks/{chunk-QXF6EQFP.js → chunk-5CMZDVUR.js} +2 -2
- package/dist/cli/chunks/{chunk-VOAXVNO5.js → chunk-5VGQABM3.js} +4 -4
- package/dist/cli/chunks/{chunk-UOO7P2AK.js → chunk-5VV5MOED.js} +2 -2
- package/dist/cli/chunks/{chunk-5IVXM3TE.js → chunk-6FICUNAV.js} +1 -1
- package/dist/cli/chunks/{chunk-LASZCR5G.js → chunk-6ITWOYET.js} +2 -2
- package/dist/cli/chunks/{chunk-7EL5QEMJ.js → chunk-6QZSF6RL.js} +2 -2
- package/dist/cli/chunks/{chunk-KDICUKYX.js → chunk-6UPQD42K.js} +2 -2
- package/dist/cli/chunks/{chunk-LJSHQU2P.js → chunk-6VUEUYFL.js} +5 -5
- package/dist/cli/chunks/{chunk-75CFWCQV.js → chunk-7225UNNY.js} +2 -2
- package/dist/cli/chunks/{chunk-L3UTZEVW.js → chunk-75QKZ6VX.js} +2 -2
- package/dist/cli/chunks/{chunk-GRMKN44A.js → chunk-7GTB7LVJ.js} +3 -3
- package/dist/cli/chunks/{chunk-EUIUWZF4.js → chunk-7KRZ2Q6B.js} +3 -3
- package/dist/cli/chunks/{chunk-ERKYIV25.js → chunk-7NYCYSGW.js} +2 -2
- package/dist/cli/chunks/{chunk-7YAHECC5.js → chunk-7TON6JSG.js} +2 -2
- package/dist/cli/chunks/chunk-ACHMNMEJ.js +2 -0
- package/dist/cli/chunks/{chunk-27FWRWOB.js → chunk-ADYY2GKC.js} +2 -2
- package/dist/cli/chunks/{chunk-NAZFAGJ5.js → chunk-AOUULKKT.js} +2 -2
- package/dist/cli/chunks/{chunk-XBSBVPSM.js → chunk-AU3APBY2.js} +2 -2
- package/dist/cli/chunks/{chunk-C3AF5Z55.js → chunk-BAOKXLIV.js} +2 -2
- package/dist/cli/chunks/{chunk-RO4BYINM.js → chunk-BDVZF46F.js} +2 -2
- package/dist/cli/chunks/{chunk-LIMFWEUI.js → chunk-BGLSIA4U.js} +2 -2
- package/dist/cli/chunks/{chunk-UNMWI4QU.js → chunk-BI6UU3Z3.js} +1 -1
- package/dist/cli/chunks/{chunk-SFRYDGLF.js → chunk-BOM5NGCR.js} +1 -1
- package/dist/cli/chunks/{chunk-QENUKXPP.js → chunk-CBXJ4AQS.js} +2 -2
- package/dist/cli/chunks/{chunk-6XCULO27.js → chunk-CKYRZ3TA.js} +2 -2
- package/dist/cli/chunks/{chunk-RLZZTFEN.js → chunk-CTILSLXF.js} +2 -2
- package/dist/cli/chunks/chunk-CVXEOTIK.js +2 -0
- package/dist/cli/chunks/{chunk-3RSF7POD.js → chunk-D777E2MT.js} +2 -2
- package/dist/cli/chunks/{chunk-FZ4MUDHZ.js → chunk-DKGDBKBJ.js} +1 -1
- package/dist/cli/chunks/{chunk-KO3UQYGY.js → chunk-DLBJ7IZT.js} +75 -75
- package/dist/cli/chunks/{chunk-56QR72EB.js → chunk-DR2M2SI2.js} +2 -2
- package/dist/cli/chunks/{chunk-MP3RCZ75.js → chunk-DS53MJCN.js} +1 -1
- package/dist/cli/chunks/{chunk-KE656E6T.js → chunk-DSIS6WQD.js} +3 -3
- package/dist/cli/chunks/{chunk-CQP6BDSF.js → chunk-DSTQ2OWI.js} +1 -1
- package/dist/cli/chunks/{chunk-WUXCL65V.js → chunk-DXM7IN2W.js} +2 -2
- package/dist/cli/chunks/{chunk-O74V7MB4.js → chunk-E3OKRZCH.js} +2 -2
- package/dist/cli/chunks/{chunk-TO7FTPRV.js → chunk-E7MD5LHC.js} +2 -2
- package/dist/cli/chunks/{chunk-A2G26WU4.js → chunk-EKWEJOV7.js} +1 -1
- package/dist/cli/chunks/chunk-EP4ORDFE.js +2 -0
- package/dist/cli/chunks/{chunk-5RVWL2U3.js → chunk-EVJSK56E.js} +3 -3
- package/dist/cli/chunks/chunk-EY44JDUL.js +12 -0
- package/dist/cli/chunks/{chunk-JDADACZZ.js → chunk-EYHRYIBX.js} +1 -1
- package/dist/cli/chunks/{chunk-FJSL7TWU.js → chunk-EYWR4Y3J.js} +1 -1
- package/dist/cli/chunks/{chunk-E7FCVH32.js → chunk-F66FYZQF.js} +2 -2
- package/dist/cli/chunks/{chunk-GNFKG2LX.js → chunk-FGQH5LOG.js} +2 -2
- package/dist/cli/chunks/{chunk-ZAT65V6I.js → chunk-FH6H4KOZ.js} +17 -17
- package/dist/cli/chunks/{chunk-OU3SYEYJ.js → chunk-FV47SYXK.js} +1 -1
- package/dist/cli/chunks/chunk-GA7PUAMT.js +2 -0
- package/dist/cli/chunks/{chunk-IVZA5XTW.js → chunk-GEH3S5DI.js} +2 -2
- package/dist/cli/chunks/{chunk-44SYMJ4T.js → chunk-GQCYO54W.js} +2 -2
- package/dist/cli/chunks/{chunk-4HVVVVUF.js → chunk-GSZL3WST.js} +2 -2
- package/dist/cli/chunks/{chunk-XTHRSBMJ.js → chunk-GV3C224P.js} +2 -2
- package/dist/cli/chunks/{chunk-JBHGMLN7.js → chunk-HBNMEYJS.js} +182 -201
- package/dist/cli/chunks/{chunk-LUAYTM77.js → chunk-HPRX5S74.js} +1 -1
- package/dist/cli/chunks/{chunk-PFQLB4XP.js → chunk-HWWMINXV.js} +2 -2
- package/dist/cli/chunks/{chunk-UQFMQOZB.js → chunk-IHUAEQZN.js} +1 -1
- package/dist/cli/chunks/{chunk-GGZB2ZBB.js → chunk-ISOTSVI7.js} +1 -1
- package/dist/cli/chunks/{chunk-RCRKCMN5.js → chunk-JDADNBWS.js} +1 -1
- package/dist/cli/chunks/{chunk-ITQCSIYG.js → chunk-JGQZ7ECC.js} +1 -1
- package/dist/cli/chunks/{chunk-5R26MAMK.js → chunk-JH6KUV74.js} +2 -2
- package/dist/cli/chunks/{chunk-6CZUQA4G.js → chunk-JPJSOS4H.js} +1 -1
- package/dist/cli/chunks/{chunk-NW4YPUPN.js → chunk-JQXAWTS5.js} +3 -3
- package/dist/cli/chunks/{chunk-II2RP3MY.js → chunk-K7ZFBGLE.js} +2 -2
- package/dist/cli/chunks/chunk-KBHSID6C.js +62 -0
- package/dist/cli/chunks/{chunk-KZAVYHH7.js → chunk-KHDE4KT5.js} +4 -4
- package/dist/cli/chunks/{chunk-LEIG3KIG.js → chunk-KMCI3RGD.js} +2 -2
- package/dist/cli/chunks/{chunk-KB4S7MGB.js → chunk-LGP26FTM.js} +2 -2
- package/dist/cli/chunks/{chunk-55E62F4T.js → chunk-LLVXOXAK.js} +1 -1
- package/dist/cli/chunks/{chunk-PIYDPOW6.js → chunk-LQYAJ7RR.js} +2 -2
- package/dist/cli/chunks/{chunk-KQLJILCZ.js → chunk-LVLGRUUJ.js} +1 -1
- package/dist/cli/chunks/{chunk-PRHLV6FS.js → chunk-LYGHX4II.js} +1 -1
- package/dist/cli/chunks/{chunk-RKNKFLCQ.js → chunk-MOIKR7RU.js} +2 -2
- package/dist/cli/chunks/chunk-MSA6MD5C.js +2 -0
- package/dist/cli/chunks/{chunk-MWWTYPFL.js → chunk-MTEEFP6V.js} +2 -2
- package/dist/cli/chunks/{chunk-OR2RC7ZH.js → chunk-N6QUDQ5H.js} +2 -2
- package/dist/cli/chunks/{chunk-Z7FVGJYC.js → chunk-N7JRGAJF.js} +2 -2
- package/dist/cli/chunks/{chunk-WCUXA3NV.js → chunk-NNIAUDHF.js} +1 -1
- package/dist/cli/chunks/{chunk-SQCACQUM.js → chunk-NUCVMWDJ.js} +2 -2
- package/dist/cli/chunks/{chunk-N57M7UPQ.js → chunk-NUDDFJYU.js} +2 -2
- package/dist/cli/chunks/{chunk-GIU26D5G.js → chunk-NX6FOAS4.js} +1 -1
- package/dist/cli/chunks/{chunk-ZYCPTARG.js → chunk-O34674VM.js} +2 -2
- package/dist/cli/chunks/{chunk-PJFQGNRW.js → chunk-OIGWREK7.js} +1 -1
- package/dist/cli/chunks/{chunk-DQ247474.js → chunk-OS56PKRO.js} +2 -2
- package/dist/cli/chunks/{chunk-OF7674H5.js → chunk-P4CHYYJN.js} +2 -2
- package/dist/cli/chunks/{chunk-VLELNETG.js → chunk-P6A35LKJ.js} +2 -2
- package/dist/cli/chunks/{chunk-GOFP47XU.js → chunk-PA6SUNDD.js} +1 -1
- package/dist/cli/chunks/{chunk-O45CEMVF.js → chunk-PGDDPZ7W.js} +1 -1
- package/dist/cli/chunks/{chunk-ESMSH7HG.js → chunk-PLYGIUFO.js} +2 -2
- package/dist/cli/chunks/{chunk-EEHEMDNV.js → chunk-POZ3S4UO.js} +2 -2
- package/dist/cli/chunks/{chunk-NQJLUY2K.js → chunk-PSAXLKDZ.js} +2 -2
- package/dist/cli/chunks/{chunk-HGY62IYZ.js → chunk-PTBW2QXE.js} +2 -2
- package/dist/cli/chunks/{chunk-PI55PHUL.js → chunk-PW3JLQGH.js} +2 -2
- package/dist/cli/chunks/{chunk-GOHWEQEP.js → chunk-PX7MVV6F.js} +2 -2
- package/dist/cli/chunks/{chunk-SJ26ZR75.js → chunk-Q4RU4XG6.js} +2 -2
- package/dist/cli/chunks/{chunk-XF4F5ZXO.js → chunk-QQA4N3YT.js} +4 -4
- package/dist/cli/chunks/chunk-QSO5RFJ4.js +15 -0
- package/dist/cli/chunks/{chunk-Z6FK7T7J.js → chunk-R2GHZ2QG.js} +2 -2
- package/dist/cli/chunks/{chunk-VDPQ7NVG.js → chunk-R5FSKAS3.js} +1 -1
- package/dist/cli/chunks/{chunk-5DESO7E4.js → chunk-R5LDNZVB.js} +2 -2
- package/dist/cli/chunks/{chunk-X5JMTHXC.js → chunk-RBNSZFVL.js} +3 -3
- package/dist/cli/chunks/{chunk-TM6LLT4G.js → chunk-RDSO3R2R.js} +3 -3
- package/dist/cli/chunks/{chunk-27REOPQK.js → chunk-SZO6JIFM.js} +2 -2
- package/dist/cli/chunks/{chunk-IU5SILCS.js → chunk-TGSL4OOT.js} +2 -2
- package/dist/cli/chunks/{chunk-4FP4PJ45.js → chunk-THW6LF5I.js} +2 -2
- package/dist/cli/chunks/{chunk-FBXWU37F.js → chunk-TMM5NKPI.js} +1 -1
- package/dist/cli/chunks/{chunk-VZO4V4R4.js → chunk-TWNXZOJY.js} +2 -2
- package/dist/cli/chunks/{chunk-X67O2KUE.js → chunk-U63JEFF5.js} +7 -7
- package/dist/cli/chunks/{chunk-IUFNB6I6.js → chunk-UHQA6EH6.js} +2 -2
- package/dist/cli/chunks/{chunk-XLP44YGX.js → chunk-UN2MXDJT.js} +2 -2
- package/dist/cli/chunks/{chunk-CTNDSP2M.js → chunk-UNLH7NPY.js} +1 -1
- package/dist/cli/chunks/{chunk-EPSF2ERW.js → chunk-V4QQTPZF.js} +2 -2
- package/dist/cli/chunks/{chunk-UAEP2ZUQ.js → chunk-V5MS6XNT.js} +2 -2
- package/dist/cli/chunks/{chunk-XEI5LLHX.js → chunk-VK5I4JSN.js} +2 -2
- package/dist/cli/chunks/{chunk-W37WY3OL.js → chunk-VSP2IB5N.js} +2 -2
- package/dist/cli/chunks/{chunk-PD2ZSCEH.js → chunk-WA553ALQ.js} +1 -1
- package/dist/cli/chunks/{chunk-TFFEB7XD.js → chunk-X3CHYV7G.js} +2 -2
- package/dist/cli/chunks/{chunk-MPVOZKUP.js → chunk-X75OYPS6.js} +1 -1
- package/dist/cli/chunks/{chunk-C75V5PTW.js → chunk-XF2TKGSC.js} +1 -1
- package/dist/cli/chunks/{chunk-Y7VWCP35.js → chunk-XLDEWLP4.js} +1 -1
- package/dist/cli/chunks/{chunk-26SNR2EK.js → chunk-XRH2D6JV.js} +3 -3
- package/dist/cli/chunks/{chunk-MANWLRAW.js → chunk-XZPAKAFJ.js} +1 -1
- package/dist/cli/chunks/{chunk-6XVP6BGM.js → chunk-Y2QZK46R.js} +2 -2
- package/dist/cli/chunks/{chunk-6BHRSGR7.js → chunk-YL7CAOQG.js} +3 -3
- package/dist/cli/chunks/{chunk-SPTCNM45.js → chunk-YOVQBSTW.js} +2 -2
- package/dist/cli/chunks/{chunk-2Q73TQUQ.js → chunk-YQUZGPUQ.js} +1 -1
- package/dist/cli/chunks/{chunk-YZGA4ELM.js → chunk-YRRYKR7U.js} +2 -2
- package/dist/cli/chunks/{chunk-NAAPL2HK.js → chunk-Z6SAS2NU.js} +1 -1
- package/dist/cli/chunks/{ci-DK4FGREO.js → ci-MWQVCZ2W.js} +2 -2
- package/dist/cli/chunks/{ci-output-HQBBQQES.js → ci-output-ZCH4IZ7H.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-MJCS46DN.js → circuit-breaker-N3VSQM5X.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-IIQT52H4.js → claude-flow-setup-TSJFOGXN.js} +2 -2
- package/dist/cli/chunks/client-IEN43WBH.js +2 -0
- package/dist/cli/chunks/{cline-installer-7SPKUNNZ.js → cline-installer-OHKWAB4I.js} +2 -2
- package/dist/cli/chunks/{code-V2B4FP3X.js → code-3UTIL3QR.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-IRGAI76Y.js → code-index-extractor-TVG2V2NY.js} +2 -2
- package/dist/cli/chunks/{codex-installer-PDFCYRU6.js → codex-installer-L6ZOTOO2.js} +2 -2
- package/dist/cli/chunks/{completions-TAJ6N7YZ.js → completions-SFRB664X.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-JHQKQKBG.js → complexity-analyzer-HDZKVO6D.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-DESZXCLC.js → continuedev-installer-HKLZR3UO.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-OQPXBLWS.js → copilot-installer-5P3LX3C5.js} +2 -2
- package/dist/cli/chunks/core-handlers-PBITKHVP.js +2 -0
- package/dist/cli/chunks/{cost-tracker-KHDFSCAJ.js → cost-tracker-MZR5RB6E.js} +2 -2
- package/dist/cli/chunks/{coverage-T7EENIDE.js → coverage-L6V6NFIM.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-JGCWQ7BO.js +2 -0
- package/dist/cli/chunks/{cursor-installer-X6BFU5QU.js → cursor-installer-FD6DT23Y.js} +2 -2
- package/dist/cli/chunks/{daemon-UTPP4JCG.js → daemon-HTSRODRG.js} +4 -4
- package/dist/cli/chunks/{daemon-22NOG5XI.js → daemon-I5ESGZGX.js} +3 -3
- package/dist/cli/chunks/{dag-attention-scheduler-XI6DG3FW.js → dag-attention-scheduler-JPTHWB2Q.js} +2 -2
- package/dist/cli/chunks/{detect-7IMQGJ5I.js → detect-RTUZDBEZ.js} +2 -2
- package/dist/cli/chunks/{dist-node-YMLM4K7J.js → dist-node-5HLWHNYA.js} +2 -2
- package/dist/cli/chunks/{domain-handler-LRTJGTEH.js → domain-handler-R7IPUX54.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-HZJ3WUCT.js → domain-transfer-E3I2LMCB.js} +2 -2
- package/dist/cli/chunks/dream-52MPUF5Q.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-QSRN7Z5Q.js → embed-and-insert-pattern-BXUWG73R.js} +2 -2
- package/dist/cli/chunks/{eval-JVVVQVV6.js → eval-3ZFM75YA.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-ORZN3ROJ.js → experience-capture-middleware-NJ3BT657.js} +3 -3
- package/dist/cli/chunks/{fast-paths-LUFARZR5.js → fast-paths-Q3V5C5IM.js} +2 -2
- package/dist/cli/chunks/{feature-flags-ZHQESXIP.js → feature-flags-D3JGPHXY.js} +2 -2
- package/dist/cli/chunks/{feature-flags-2XC4ECLW.js → feature-flags-XZGJNPZ7.js} +2 -2
- package/dist/cli/chunks/file-discovery-MZOYXIOS.js +2 -0
- package/dist/cli/chunks/{fleet-FUQ6G4SB.js → fleet-FG3EBA75.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-A4E6OKGD.js → gnn-wrapper-PKZLZHL2.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-3JKQORXA.js → heartbeat-handler-YZTRVH75.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-LMAEJQYQ.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-DGGDYJEL.js +2 -0
- package/dist/cli/chunks/hnsw-index-KA7WDTHX.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-AHKFKM2J.js → hnsw-legacy-bridge-WONHB63F.js} +2 -2
- package/dist/cli/chunks/hnswlib-node-Q4VPSJJM.js +2 -0
- package/dist/cli/chunks/{hooks-JNW5ZB2E.js → hooks-RWX5ZZCE.js} +47 -47
- package/dist/cli/chunks/hybrid-router-Q6JQTV55.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-3DTAMNSJ.js → hypergraph-engine-G6N24L5G.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-ZV4AZRGF.js → hypergraph-handler-4RGOLL6F.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-7LFSGIQP.js +2 -0
- package/dist/cli/chunks/{init-handler-NPOUX47N.js → init-handler-L7DZAHXO.js} +12 -12
- package/dist/cli/chunks/init-wizard-T4K44J6D.js +2 -0
- package/dist/cli/chunks/kernel-TGHK6X7F.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-D35TR6LG.js → kilocode-installer-G7PUCUDZ.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-OHHTQENO.js → kiro-installer-H6234HEB.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-MV3OSGCB.js +2 -0
- package/dist/cli/chunks/learning-346CA4DH.js +119 -0
- package/dist/cli/chunks/{llm-router-XLTE52H5.js → llm-router-ATNRDTEM.js} +4 -4
- package/dist/cli/chunks/llm-router-service-OOCNAPJO.js +2 -0
- package/dist/cli/chunks/{load-BHMK4FIL.js → load-3L2CK4ML.js} +2 -2
- package/dist/cli/chunks/load-test-4OZPYWL4.js +2 -0
- package/dist/cli/chunks/{mcp-V4MAYT7C.js → mcp-JJ4ZDUJB.js} +2 -2
- package/dist/cli/chunks/{memory-PDA7MQ7E.js → memory-U3K2Y777.js} +5 -5
- package/dist/cli/chunks/memory-backend-LMRIHJQY.js +2 -0
- package/dist/cli/chunks/memory-handlers-J6CVQ5DS.js +2 -0
- package/dist/cli/chunks/{multi-model-executor-KECHOXKD.js → multi-model-executor-DPCU4CSM.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-LWSCQOOZ.js → opencode-installer-KNUCUSRG.js} +2 -2
- package/dist/cli/chunks/{orchestrator-ENEBTEUW.js → orchestrator-DJV2NUWD.js} +11 -11
- package/dist/cli/chunks/pattern-null-store-AQWPHLRW.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-XIHGXYZZ.js → pattern-usage-recorder-TQ7KECBB.js} +2 -2
- package/dist/cli/chunks/{pipeline-GQOJM3LU.js → pipeline-JG57VFOB.js} +2 -2
- package/dist/cli/chunks/{platform-L56TGXGZ.js → platform-L7LOBG4E.js} +2 -2
- package/dist/cli/chunks/{plugin-SZ6PZKYX.js → plugin-ATBPEU2K.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-SID5FQFW.js → prime-radiant-advanced-wasm-XCX7CNVW.js} +2 -2
- package/dist/cli/chunks/protocol-executor-FWUT6L6K.js +2 -0
- package/dist/cli/chunks/{protocol-handler-5MMNVVPX.js → protocol-handler-DOFLSB4N.js} +2 -2
- package/dist/cli/chunks/{prove-DJ6BQ2AK.js → prove-CDBMRPBD.js} +2 -2
- package/dist/cli/chunks/provider-manager-4PY7IR3V.js +2 -0
- package/dist/cli/chunks/qe-reasoning-bank-M4XVWRPY.js +2 -0
- package/dist/cli/chunks/quality-5CMQBYP3.js +7 -0
- package/dist/cli/chunks/{quality-gate-CVHVSORK.js → quality-gate-LU66IWRT.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-KSRI42QZ.js +2 -0
- package/dist/cli/chunks/{real-embeddings-DN2MEJVM.js → real-embeddings-3B7AXYOP.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-LTAQJWIH.js → roocode-installer-GF4YJW7E.js} +2 -2
- package/dist/cli/chunks/router-F2TCXNSG.js +2 -0
- package/dist/cli/chunks/routing-feedback-VHOWXUY7.js +2 -0
- package/dist/cli/chunks/{routing-handler-PSWR2UCT.js → routing-handler-PWQMWFND.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-VTP6Y7PN.js → ruvector-commands-SMD6KSBD.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-EBUMXPRO.js → rvf-dual-writer-M5TEJ56X.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-5N7GHMD3.js → rvf-migration-adapter-EHLWMZYI.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-GQKDBNRR.js → rvf-migration-coordinator-GMVLX3FX.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-XG3LFOYW.js +2 -0
- package/dist/cli/chunks/{rvf-store-integrity-LR3SYGQK.js → rvf-store-integrity-PDADEHAZ.js} +2 -2
- package/dist/cli/chunks/safe-db-CTHJ3SXC.js +2 -0
- package/dist/cli/chunks/schedule-LLYADLGL.js +2 -0
- package/dist/cli/chunks/scheduler-72YIGDIX.js +2 -0
- package/dist/cli/chunks/{security-YDWLYXYD.js → security-PSMBTUSM.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-I3HQY7DE.js → shared-rvf-adapter-DP2Z4YLV.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-2UADEA5N.js → shared-rvf-dual-writer-UOU6ORBJ.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-N7OO3ZOE.js +2 -0
- package/dist/cli/chunks/{status-handler-QRHI3F4V.js → status-handler-T565F47D.js} +2 -2
- package/dist/cli/chunks/{structural-health-FWKE63CM.js → structural-health-54WNSZ7Y.js} +2 -2
- package/dist/cli/chunks/{sync-2QRCT5MT.js → sync-5ZGYF7JF.js} +2 -2
- package/dist/cli/chunks/{sync-E32MBAOF.js → sync-EXADT5IZ.js} +2 -2
- package/dist/cli/chunks/{task-handler-C7BKMOCL.js → task-handler-JXWQZDEX.js} +2 -2
- package/dist/cli/chunks/{task-handlers-PADWLLDO.js → task-handlers-UKHRILMM.js} +3 -3
- package/dist/cli/chunks/test-3SU56PMM.js +33 -0
- package/dist/cli/chunks/{test-scheduling-5WKIWH4H.js → test-scheduling-CZZ4KKWM.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-6SKOJM3U.js → token-bootstrap-RSIAPUIV.js} +2 -2
- package/dist/cli/chunks/{token-usage-V6JW55RV.js → token-usage-7HW43ORO.js} +2 -2
- package/dist/cli/chunks/{transformers-3UPFBYSB.js → transformers-A5REG7OI.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-UCY4S2DU.js → tree-sitter-wasm-parser-F43MC7E5.js} +2 -2
- package/dist/cli/chunks/{types-XNMNQGET.js → types-DEOHTTJ3.js} +2 -2
- package/dist/cli/chunks/unified-memory-Q55MJWAM.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-4BEKV2K5.js +2 -0
- package/dist/cli/chunks/unified-persistence-IIB5MR67.js +2 -0
- package/dist/cli/chunks/{upgrade-MVTMTOPL.js → upgrade-7NKNCL2I.js} +2 -2
- package/dist/cli/chunks/{validate-OJWR2AGZ.js → validate-SN2UY7CT.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-2RGSF2K2.js → validate-swarm-YITFMCXY.js} +2 -2
- package/dist/cli/chunks/{vibium-O3ZLAEEZ.js → vibium-AZNIG6O7.js} +2 -2
- package/dist/cli/chunks/visual-security-F4FUP6KV.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-6VPASTI4.js → web-tree-sitter-DY4YXPMR.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-CINHOW3N.js → windsurf-installer-HXD4BK7N.js} +2 -2
- package/dist/cli/chunks/witness-chain-SQ5LCKUQ.js +2 -0
- package/dist/cli/chunks/{witness-chain-2NXW7FT7.js → witness-chain-UV7BOO6T.js} +2 -2
- package/dist/cli/chunks/{witness-key-manager-ODW4DJWT.js → witness-key-manager-BCNW3SZH.js} +2 -2
- package/dist/cli/chunks/{workflow-BFGS2GAU.js → workflow-R3SSSWA5.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-Z4PZXWVY.js +2 -0
- package/dist/cli/chunks/{wrappers-VEVVSVMS.js → wrappers-6JUXYAML.js} +2 -2
- package/dist/cli/commands/hooks-handlers/hooks-dream-learning.js +16 -27
- package/dist/cli/commands/learning.js +66 -0
- package/dist/cli/commands/quality.d.ts +12 -0
- package/dist/cli/commands/quality.js +50 -74
- package/dist/cli/commands/test.js +33 -4
- package/dist/cli/handlers/init-handler.d.ts +2 -0
- package/dist/cli/handlers/init-handler.js +4 -1
- package/dist/cli/utils/file-discovery.d.ts +1 -0
- package/dist/cli/utils/file-discovery.js +13 -1
- package/dist/domains/coverage-analysis/services/coverage-analyzer.js +5 -0
- package/dist/domains/quality-assessment/index.d.ts +1 -0
- package/dist/domains/quality-assessment/index.js +1 -0
- package/dist/domains/quality-assessment/quality-evidence.d.ts +41 -0
- package/dist/domains/quality-assessment/quality-evidence.js +115 -0
- package/dist/domains/test-execution/coordinator.d.ts +1 -0
- package/dist/domains/test-execution/coordinator.js +11 -4
- package/dist/domains/test-execution/interfaces.d.ts +2 -0
- package/dist/domains/test-execution/services/retry-handler.js +3 -3
- package/dist/domains/test-execution/services/test-executor.d.ts +5 -0
- package/dist/domains/test-execution/services/test-executor.js +93 -30
- package/dist/domains/test-generation/gates/test-quality-gate.d.ts +8 -2
- package/dist/domains/test-generation/gates/test-quality-gate.js +93 -4
- package/dist/domains/test-generation/generators/base-test-generator.js +0 -15
- package/dist/domains/test-generation/generators/jest-vitest-generator.js +17 -26
- package/dist/domains/test-generation/services/test-generator.js +7 -2
- package/dist/init/orchestrator.js +1 -0
- package/dist/init/phases/07-hooks.js +3 -1
- package/dist/init/phases/phase-interface.d.ts +2 -0
- package/dist/init/settings-merge.d.ts +3 -1
- package/dist/init/settings-merge.js +9 -3
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.d.ts +2 -0
- package/dist/integrations/agentic-flow/reasoning-bank/experience-replay.js +14 -0
- package/dist/integrations/embeddings/index/HNSWIndex.js +2 -0
- package/dist/kernel/hybrid-backend.d.ts +1 -1
- package/dist/kernel/hybrid-backend.js +2 -2
- package/dist/kernel/interfaces.d.ts +2 -2
- package/dist/kernel/memory-backend.d.ts +1 -1
- package/dist/kernel/memory-backend.js +3 -1
- package/dist/kernel/unified-memory.d.ts +1 -1
- package/dist/kernel/unified-memory.js +19 -4
- package/dist/learning/real-embeddings.js +20 -4
- package/dist/learning/sqlite-persistence.d.ts +3 -2
- package/dist/learning/sqlite-persistence.js +7 -8
- package/dist/mcp/bundle.js +453 -472
- package/dist/mcp/handlers/memory-handlers.js +2 -5
- package/dist/mcp/tools/quality-assessment/evaluate.d.ts +7 -0
- package/dist/mcp/tools/quality-assessment/evaluate.js +72 -20
- package/dist/mcp/tools/security-compliance/scan.js +8 -1
- package/package.json +2 -2
- package/dist/cli/chunks/adapter-JISQ35YY.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-TVTNP76S.js +0 -2
- package/dist/cli/chunks/base-WBCYKM45.js +0 -2
- package/dist/cli/chunks/better-sqlite3-FXJFG2WH.js +0 -2
- package/dist/cli/chunks/browser-workflow-4JM3IWCS.js +0 -2
- package/dist/cli/chunks/chunk-344CLTV7.js +0 -62
- package/dist/cli/chunks/chunk-6VNUASTQ.js +0 -15
- package/dist/cli/chunks/chunk-CW7LDLJ2.js +0 -2
- package/dist/cli/chunks/chunk-HGBVGEUE.js +0 -2
- package/dist/cli/chunks/chunk-JJ5YIKTJ.js +0 -12
- package/dist/cli/chunks/chunk-QGH54HTH.js +0 -2
- package/dist/cli/chunks/chunk-TCYSMSBO.js +0 -2
- package/dist/cli/chunks/chunk-YQI6SOUO.js +0 -2
- package/dist/cli/chunks/client-FNDZB4TY.js +0 -2
- package/dist/cli/chunks/core-handlers-S37RHLKP.js +0 -2
- package/dist/cli/chunks/cross-domain-router-7ZHDB2V3.js +0 -2
- package/dist/cli/chunks/dream-BEVYNIOO.js +0 -2
- package/dist/cli/chunks/file-discovery-UHXZQ7GS.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-K4YLB3X4.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-PPR3LTMA.js +0 -2
- package/dist/cli/chunks/hnsw-index-ZSKFT4LZ.js +0 -2
- package/dist/cli/chunks/hybrid-router-4SXBHTOY.js +0 -2
- package/dist/cli/chunks/impact-analyzer-55GE7EQD.js +0 -2
- package/dist/cli/chunks/init-wizard-EUQLSGI6.js +0 -2
- package/dist/cli/chunks/kernel-BSGSVYPM.js +0 -2
- package/dist/cli/chunks/knowledge-graph-OITIVT5J.js +0 -2
- package/dist/cli/chunks/learning-24PCHLWU.js +0 -117
- package/dist/cli/chunks/llm-router-service-RUPU52AR.js +0 -2
- package/dist/cli/chunks/load-test-ZV3C55ZE.js +0 -2
- package/dist/cli/chunks/memory-backend-S3KCPHCF.js +0 -2
- package/dist/cli/chunks/memory-handlers-X5BLXOSH.js +0 -2
- package/dist/cli/chunks/pattern-null-store-ILVDKSCX.js +0 -2
- package/dist/cli/chunks/protocol-executor-GDRHCW3Q.js +0 -2
- package/dist/cli/chunks/provider-manager-BS4MVCSH.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-P3ARGHDN.js +0 -2
- package/dist/cli/chunks/quality-WKC4JCB3.js +0 -7
- package/dist/cli/chunks/queen-coordinator-GI7GNVDM.js +0 -2
- package/dist/cli/chunks/router-YU6MLJBV.js +0 -2
- package/dist/cli/chunks/routing-feedback-D6B2SK5V.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-M7ZVRN5Z.js +0 -2
- package/dist/cli/chunks/safe-db-3OHTLXG7.js +0 -2
- package/dist/cli/chunks/schedule-H43ADREQ.js +0 -2
- package/dist/cli/chunks/scheduler-CGSXNEPJ.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-V6U5FKVK.js +0 -2
- package/dist/cli/chunks/test-KX4UKHSX.js +0 -33
- package/dist/cli/chunks/unified-memory-H2J5BHPY.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-LFGIWMTS.js +0 -2
- package/dist/cli/chunks/unified-persistence-F6W7EXU5.js +0 -2
- package/dist/cli/chunks/visual-security-EHVU32UE.js +0 -2
- package/dist/cli/chunks/witness-chain-BIICGRHC.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-PVTYPYY4.js +0 -2
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
export const QUALITY_EVIDENCE_NAMESPACE = 'quality-assessment';
|
|
2
|
+
export const DEFAULT_QUALITY_EVIDENCE_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
3
|
+
export const QUALITY_METRICS = [
|
|
4
|
+
'coverage',
|
|
5
|
+
'testsPassing',
|
|
6
|
+
'criticalBugs',
|
|
7
|
+
'codeSmells',
|
|
8
|
+
'securityVulnerabilities',
|
|
9
|
+
'technicalDebt',
|
|
10
|
+
'duplications',
|
|
11
|
+
];
|
|
12
|
+
export const DEFAULT_QUALITY_THRESHOLDS = {
|
|
13
|
+
coverage: { direction: 'min', value: 80, severity: 'high' },
|
|
14
|
+
testsPassing: { direction: 'min', value: 95, severity: 'critical' },
|
|
15
|
+
criticalBugs: { direction: 'max', value: 0, severity: 'critical' },
|
|
16
|
+
codeSmells: { direction: 'max', value: 20, severity: 'medium' },
|
|
17
|
+
securityVulnerabilities: { direction: 'max', value: 0, severity: 'critical' },
|
|
18
|
+
technicalDebt: { direction: 'max', value: 5, severity: 'medium' },
|
|
19
|
+
duplications: { direction: 'max', value: 5, severity: 'low' },
|
|
20
|
+
};
|
|
21
|
+
function evidenceKey(metric) {
|
|
22
|
+
return `quality-evidence:${metric}:latest`;
|
|
23
|
+
}
|
|
24
|
+
function parseMeasuredAt(measuredAt, now, maxAgeMs) {
|
|
25
|
+
if (typeof measuredAt !== 'string') {
|
|
26
|
+
throw new Error('Measured quality evidence is malformed: measuredAt is required.');
|
|
27
|
+
}
|
|
28
|
+
const timestamp = Date.parse(measuredAt);
|
|
29
|
+
if (!Number.isFinite(timestamp)) {
|
|
30
|
+
throw new Error('Measured quality evidence is malformed: measuredAt is invalid.');
|
|
31
|
+
}
|
|
32
|
+
if (timestamp > now + 60_000) {
|
|
33
|
+
throw new Error('Measured quality evidence is malformed: measuredAt is in the future.');
|
|
34
|
+
}
|
|
35
|
+
if (now - timestamp > maxAgeMs) {
|
|
36
|
+
throw new Error('Measured quality evidence is stale. Run the relevant quality analyzers again.');
|
|
37
|
+
}
|
|
38
|
+
return timestamp;
|
|
39
|
+
}
|
|
40
|
+
function validateRecord(record, metric, now, maxAgeMs) {
|
|
41
|
+
if (!record || typeof record !== 'object') {
|
|
42
|
+
throw new Error(`No measured quality evidence found for ${metric}.`);
|
|
43
|
+
}
|
|
44
|
+
const candidate = record;
|
|
45
|
+
if (candidate.schemaVersion !== 1
|
|
46
|
+
|| candidate.metric !== metric
|
|
47
|
+
|| !Number.isFinite(candidate.value)
|
|
48
|
+
|| candidate.value < 0
|
|
49
|
+
|| typeof candidate.source !== 'string'
|
|
50
|
+
|| candidate.source.trim().length === 0) {
|
|
51
|
+
throw new Error(`Measured quality evidence for ${metric} is malformed or incomplete.`);
|
|
52
|
+
}
|
|
53
|
+
parseMeasuredAt(candidate.measuredAt, now, maxAgeMs);
|
|
54
|
+
}
|
|
55
|
+
export async function writeQualityEvidence(memory, values, metadata) {
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
parseMeasuredAt(metadata.measuredAt, now, Number.POSITIVE_INFINITY);
|
|
58
|
+
if (metadata.source.trim().length === 0) {
|
|
59
|
+
throw new Error('Quality evidence source is required.');
|
|
60
|
+
}
|
|
61
|
+
for (const metric of QUALITY_METRICS) {
|
|
62
|
+
const value = values[metric];
|
|
63
|
+
if (value === undefined)
|
|
64
|
+
continue;
|
|
65
|
+
if (!Number.isFinite(value) || value < 0) {
|
|
66
|
+
throw new Error(`Quality evidence value for ${metric} must be a non-negative finite number.`);
|
|
67
|
+
}
|
|
68
|
+
const record = {
|
|
69
|
+
schemaVersion: 1,
|
|
70
|
+
metric,
|
|
71
|
+
value,
|
|
72
|
+
measuredAt: metadata.measuredAt,
|
|
73
|
+
source: metadata.source,
|
|
74
|
+
};
|
|
75
|
+
await memory.set(evidenceKey(metric), record, {
|
|
76
|
+
namespace: QUALITY_EVIDENCE_NAMESPACE,
|
|
77
|
+
persist: true,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export async function loadQualityEvidence(memory, options = {}) {
|
|
82
|
+
const now = options.now ?? Date.now();
|
|
83
|
+
const maxAgeMs = options.maxAgeMs ?? DEFAULT_QUALITY_EVIDENCE_MAX_AGE_MS;
|
|
84
|
+
const values = {};
|
|
85
|
+
for (const metric of QUALITY_METRICS) {
|
|
86
|
+
const record = await memory.get(evidenceKey(metric), {
|
|
87
|
+
namespace: QUALITY_EVIDENCE_NAMESPACE,
|
|
88
|
+
});
|
|
89
|
+
validateRecord(record, metric, now, maxAgeMs);
|
|
90
|
+
values[metric] = record.value;
|
|
91
|
+
}
|
|
92
|
+
return values;
|
|
93
|
+
}
|
|
94
|
+
export function evaluateQualityEvidence(values) {
|
|
95
|
+
const checks = QUALITY_METRICS.map((name) => {
|
|
96
|
+
const threshold = DEFAULT_QUALITY_THRESHOLDS[name];
|
|
97
|
+
const value = values[name];
|
|
98
|
+
return {
|
|
99
|
+
name,
|
|
100
|
+
value,
|
|
101
|
+
threshold: threshold.value,
|
|
102
|
+
direction: threshold.direction,
|
|
103
|
+
severity: threshold.severity,
|
|
104
|
+
passed: threshold.direction === 'min' ? value >= threshold.value : value <= threshold.value,
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
passed: checks.every((check) => check.passed),
|
|
109
|
+
checks,
|
|
110
|
+
recommendations: checks
|
|
111
|
+
.filter((check) => !check.passed)
|
|
112
|
+
.map((check) => `${check.name} failed its measured ${check.direction} threshold.`),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=quality-evidence.js.map
|
|
@@ -20,6 +20,7 @@ import type { WeakVertex } from '../../coordination/mincut/interfaces';
|
|
|
20
20
|
import { BaseDomainCoordinator, type BaseDomainCoordinatorConfig } from '../base-domain-coordinator.js';
|
|
21
21
|
import type { InfraHealingOrchestrator } from '../../strange-loop/infra-healing/infra-healing-orchestrator.js';
|
|
22
22
|
import { type TestNode, type TestOptimizationResult } from './services/mincut-test-optimizer.js';
|
|
23
|
+
export declare function calculateRetryStrategyConfidence(testCount: number): number;
|
|
23
24
|
/**
|
|
24
25
|
* Configuration for the test execution coordinator
|
|
25
26
|
*/
|
|
@@ -16,6 +16,12 @@ import { createDomainFinding, } from '../../coordination/consensus/domain-findin
|
|
|
16
16
|
import { BaseDomainCoordinator, } from '../base-domain-coordinator.js';
|
|
17
17
|
import { toError } from '../../shared/error-utils.js';
|
|
18
18
|
import { createMinCutTestOptimizer, } from './services/mincut-test-optimizer.js';
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Coordinator Configuration
|
|
21
|
+
// ============================================================================
|
|
22
|
+
export function calculateRetryStrategyConfidence(testCount) {
|
|
23
|
+
return Math.min(1, 0.7 + (testCount / 100));
|
|
24
|
+
}
|
|
19
25
|
const DEFAULT_COORDINATOR_CONFIG = {
|
|
20
26
|
simulateForTesting: false,
|
|
21
27
|
enablePrioritization: true,
|
|
@@ -127,9 +133,11 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
127
133
|
failed: 0, skipped: 0, duration: 0, failedTests: [],
|
|
128
134
|
});
|
|
129
135
|
}
|
|
130
|
-
const framework = this.detectFramework(testsToRun);
|
|
136
|
+
const framework = request.framework ?? this.detectFramework(testsToRun);
|
|
131
137
|
const workers = request.workers ?? Math.min(4, Math.max(1, testsToRun.length));
|
|
132
|
-
|
|
138
|
+
// Batched runners own internal parallelism, so the timeout applies to the
|
|
139
|
+
// whole discovered suite rather than one file.
|
|
140
|
+
const timeout = request.timeout ?? Math.max(60000, testsToRun.length * 2000);
|
|
133
141
|
// Use parallel execution by default (unless explicitly disabled)
|
|
134
142
|
if (request.parallel !== false && testsToRun.length > 1) {
|
|
135
143
|
const result = await this.executeParallel({
|
|
@@ -473,8 +481,7 @@ export class TestExecutionCoordinator extends BaseDomainCoordinator {
|
|
|
473
481
|
testCount: testsToRetry.length,
|
|
474
482
|
maxRetries: request.maxRetries,
|
|
475
483
|
backoffType: request.backoff ?? 'exponential',
|
|
476
|
-
},
|
|
477
|
-
);
|
|
484
|
+
}, calculateRetryStrategyConfidence(testsToRetry.length));
|
|
478
485
|
if (!isStrategyVerified) {
|
|
479
486
|
logger.warn(`Retry strategy not verified, proceeding with reduced retries`);
|
|
480
487
|
request = { ...request, maxRetries: Math.max(1, Math.floor(request.maxRetries / 2)) };
|
|
@@ -37,6 +37,8 @@ export type TestExecutionAPI = ITestExecutionAPI;
|
|
|
37
37
|
export interface ISimpleTestRequest {
|
|
38
38
|
/** Test files to execute */
|
|
39
39
|
testFiles: string[];
|
|
40
|
+
/** Explicit test framework; auto-detected when omitted */
|
|
41
|
+
framework?: string;
|
|
40
42
|
/** Run tests in parallel (default: true) */
|
|
41
43
|
parallel?: boolean;
|
|
42
44
|
/** Number of retry attempts for failed tests (default: 0) */
|
|
@@ -339,7 +339,7 @@ export class RetryHandlerService {
|
|
|
339
339
|
// vitest run --reporter=json testFile -t "testName"
|
|
340
340
|
{
|
|
341
341
|
const vitestArgs = ['vitest', 'run', '--reporter=json', testFile];
|
|
342
|
-
if (testName) {
|
|
342
|
+
if (testName && testName !== testFile) {
|
|
343
343
|
vitestArgs.push('-t', testName);
|
|
344
344
|
}
|
|
345
345
|
return { command: npx, args: vitestArgs };
|
|
@@ -348,7 +348,7 @@ export class RetryHandlerService {
|
|
|
348
348
|
// jest --json testFile -t "testName"
|
|
349
349
|
{
|
|
350
350
|
const jestArgs = ['jest', '--json', '--testPathPattern', testFile];
|
|
351
|
-
if (testName) {
|
|
351
|
+
if (testName && testName !== testFile) {
|
|
352
352
|
jestArgs.push('-t', testName);
|
|
353
353
|
}
|
|
354
354
|
return { command: npx, args: jestArgs };
|
|
@@ -357,7 +357,7 @@ export class RetryHandlerService {
|
|
|
357
357
|
// mocha --reporter json testFile --grep "testName"
|
|
358
358
|
{
|
|
359
359
|
const mochaArgs = ['mocha', '--reporter', 'json', testFile];
|
|
360
|
-
if (testName) {
|
|
360
|
+
if (testName && testName !== testFile) {
|
|
361
361
|
mochaArgs.push('--grep', testName);
|
|
362
362
|
}
|
|
363
363
|
return { command: npx, args: mochaArgs };
|
|
@@ -105,6 +105,7 @@ export declare class TestExecutorService implements ITestExecutionService {
|
|
|
105
105
|
private validateParallelRequest;
|
|
106
106
|
private runTests;
|
|
107
107
|
private executeTestFile;
|
|
108
|
+
private executeTestFiles;
|
|
108
109
|
/**
|
|
109
110
|
* Spawn actual test runner process (vitest, jest, mocha)
|
|
110
111
|
*/
|
|
@@ -117,6 +118,10 @@ export declare class TestExecutorService implements ITestExecutionService {
|
|
|
117
118
|
* Parse test runner output to extract results
|
|
118
119
|
*/
|
|
119
120
|
private parseTestOutput;
|
|
121
|
+
/**
|
|
122
|
+
* Parse the TAP or spec summary emitted by Node's built-in test runner.
|
|
123
|
+
*/
|
|
124
|
+
private parseNodeTestOutput;
|
|
120
125
|
/**
|
|
121
126
|
* Parse vitest JSON output
|
|
122
127
|
*/
|
|
@@ -12,6 +12,7 @@ import { TEST_EXECUTION_CONSTANTS, LLM_ANALYSIS_CONSTANTS } from '../../constant
|
|
|
12
12
|
import { toErrorMessage, toError } from '../../../shared/error-utils.js';
|
|
13
13
|
import { safeJsonParse } from '../../../shared/safe-json.js';
|
|
14
14
|
import { secureRandom, secureRandomInt } from '../../../shared/utils/crypto-random.js';
|
|
15
|
+
import { writeQualityEvidence } from '../../quality-assessment/quality-evidence.js';
|
|
15
16
|
const DEFAULT_CONFIG = {
|
|
16
17
|
simulateForTesting: false,
|
|
17
18
|
simulatedTestsPerFile: 5,
|
|
@@ -102,8 +103,10 @@ export class TestExecutorService {
|
|
|
102
103
|
return err(validation.error);
|
|
103
104
|
}
|
|
104
105
|
const { workers, sharding = 'file', isolation = 'process' } = request;
|
|
106
|
+
const runnerOwnsParallelism = ['vitest', 'jest'].includes(request.framework.toLowerCase());
|
|
107
|
+
const processWorkers = runnerOwnsParallelism ? 1 : workers;
|
|
105
108
|
// Shard tests across workers
|
|
106
|
-
const shards = this.shardTests(request.testFiles,
|
|
109
|
+
const shards = this.shardTests(request.testFiles, processWorkers, sharding);
|
|
107
110
|
// Execute shards in parallel
|
|
108
111
|
const shardResults = await Promise.all(shards.map((shard, index) => this.executeWorker(shard, index, isolation, request)));
|
|
109
112
|
// Aggregate results
|
|
@@ -132,7 +135,7 @@ export class TestExecutorService {
|
|
|
132
135
|
endTime,
|
|
133
136
|
duration,
|
|
134
137
|
testsPerSecond: aggregated.total / (duration / 1000),
|
|
135
|
-
workers,
|
|
138
|
+
workers: processWorkers,
|
|
136
139
|
memoryUsage: process.memoryUsage?.().heapUsed ?? 0,
|
|
137
140
|
};
|
|
138
141
|
this.runStats.set(runId, stats);
|
|
@@ -327,26 +330,29 @@ Provide:
|
|
|
327
330
|
};
|
|
328
331
|
}
|
|
329
332
|
async executeTestFile(file, framework, timeout) {
|
|
333
|
+
return this.executeTestFiles([file], framework, timeout);
|
|
334
|
+
}
|
|
335
|
+
async executeTestFiles(files, framework, timeout) {
|
|
330
336
|
// In simulation mode (for unit testing), use random behavior
|
|
331
337
|
if (this.config.simulateForTesting) {
|
|
332
|
-
return this.simulateTestExecution(file);
|
|
338
|
+
return this.aggregateResults(files.map(file => this.simulateTestExecution(file)));
|
|
333
339
|
}
|
|
334
340
|
// Production mode: spawn actual test runner process
|
|
335
|
-
const result = await this.spawnTestRunner(
|
|
341
|
+
const result = await this.spawnTestRunner(files, framework, timeout);
|
|
336
342
|
if (result.success === false) {
|
|
337
343
|
// Return as a failed test rather than throwing — allows other files to still run
|
|
338
344
|
return {
|
|
339
|
-
total:
|
|
345
|
+
total: files.length,
|
|
340
346
|
passed: 0,
|
|
341
|
-
failed:
|
|
347
|
+
failed: files.length,
|
|
342
348
|
skipped: 0,
|
|
343
|
-
failedTests:
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
349
|
+
failedTests: files.map(file => ({
|
|
350
|
+
testId: file,
|
|
351
|
+
testName: file,
|
|
352
|
+
file,
|
|
353
|
+
error: result.error.message,
|
|
354
|
+
duration: 0,
|
|
355
|
+
})),
|
|
350
356
|
coverage: this.aggregateCoverage([]),
|
|
351
357
|
};
|
|
352
358
|
}
|
|
@@ -355,13 +361,15 @@ Provide:
|
|
|
355
361
|
/**
|
|
356
362
|
* Spawn actual test runner process (vitest, jest, mocha)
|
|
357
363
|
*/
|
|
358
|
-
async spawnTestRunner(
|
|
364
|
+
async spawnTestRunner(files, framework, timeout) {
|
|
359
365
|
// Verify test file exists
|
|
360
|
-
|
|
361
|
-
|
|
366
|
+
const missingFile = files.find(file => !existsSync(file));
|
|
367
|
+
if (missingFile) {
|
|
368
|
+
return err(new Error(`Test file not found: ${missingFile}`));
|
|
362
369
|
}
|
|
363
370
|
// Build command based on framework
|
|
364
|
-
const { command, args } = this.buildTestCommand(
|
|
371
|
+
const { command, args } = this.buildTestCommand(files, framework);
|
|
372
|
+
const fileLabel = files.join(', ');
|
|
365
373
|
return new Promise((resolve) => {
|
|
366
374
|
let stdout = '';
|
|
367
375
|
let stderr = '';
|
|
@@ -381,7 +389,7 @@ Provide:
|
|
|
381
389
|
const timeoutId = setTimeout(() => {
|
|
382
390
|
killed = true;
|
|
383
391
|
proc.kill('SIGTERM');
|
|
384
|
-
resolve(err(new Error(`Test execution timed out after ${timeout}ms for
|
|
392
|
+
resolve(err(new Error(`Test execution timed out after ${timeout}ms for files: ${fileLabel}`)));
|
|
385
393
|
}, timeout);
|
|
386
394
|
proc.stdout?.on('data', (data) => {
|
|
387
395
|
stdout += data.toString();
|
|
@@ -395,10 +403,10 @@ Provide:
|
|
|
395
403
|
return; // Already handled by timeout
|
|
396
404
|
}
|
|
397
405
|
// Parse results based on framework
|
|
398
|
-
const parseResult = this.parseTestOutput(stdout, stderr,
|
|
406
|
+
const parseResult = this.parseTestOutput(stdout, stderr, fileLabel, framework, code);
|
|
399
407
|
// If no coverage in stdout JSON, try reading from disk
|
|
400
408
|
// (vitest/jest write coverage to coverage/coverage-summary.json)
|
|
401
|
-
if (parseResult.success && !parseResult.value.coverage) {
|
|
409
|
+
if (parseResult.success && !parseResult.value.coverage && ['vitest', 'jest'].includes(framework.toLowerCase())) {
|
|
402
410
|
const diskCoverage = this.readCoverageFromDisk();
|
|
403
411
|
if (diskCoverage) {
|
|
404
412
|
parseResult.value.coverage = diskCoverage.summary;
|
|
@@ -418,33 +426,37 @@ Provide:
|
|
|
418
426
|
/**
|
|
419
427
|
* Build test command based on framework
|
|
420
428
|
*/
|
|
421
|
-
buildTestCommand(
|
|
429
|
+
buildTestCommand(fileOrFiles, framework) {
|
|
430
|
+
const files = Array.isArray(fileOrFiles) ? fileOrFiles : [fileOrFiles];
|
|
422
431
|
switch (framework.toLowerCase()) {
|
|
423
432
|
case 'vitest':
|
|
424
433
|
return {
|
|
425
434
|
command: 'npx',
|
|
426
|
-
args: ['vitest', 'run',
|
|
427
|
-
'--coverage', '--coverage.reporter=json'],
|
|
435
|
+
args: ['vitest', 'run', ...files, '--reporter=json', '--no-color'],
|
|
428
436
|
};
|
|
429
437
|
case 'jest':
|
|
430
438
|
return {
|
|
431
439
|
command: 'npx',
|
|
432
|
-
args: ['jest',
|
|
433
|
-
'--coverage', '--coverageReporters=json'],
|
|
440
|
+
args: ['jest', ...files, '--json', '--no-colors', '--testLocationInResults'],
|
|
434
441
|
};
|
|
435
442
|
case 'mocha':
|
|
436
443
|
// Note: mocha has no built-in coverage — requires external nyc/c8 wrapper.
|
|
437
444
|
// Coverage data will be unavailable for mocha-based test runs.
|
|
438
445
|
return {
|
|
439
446
|
command: 'npx',
|
|
440
|
-
args: ['mocha',
|
|
447
|
+
args: ['mocha', ...files, '--reporter=json'],
|
|
448
|
+
};
|
|
449
|
+
case 'node':
|
|
450
|
+
case 'node-test':
|
|
451
|
+
return {
|
|
452
|
+
command: process.execPath,
|
|
453
|
+
args: ['--test', ...files],
|
|
441
454
|
};
|
|
442
455
|
default:
|
|
443
456
|
// Default to vitest
|
|
444
457
|
return {
|
|
445
458
|
command: 'npx',
|
|
446
|
-
args: ['vitest', 'run',
|
|
447
|
-
'--coverage', '--coverage.reporter=json'],
|
|
459
|
+
args: ['vitest', 'run', ...files, '--reporter=json', '--no-color'],
|
|
448
460
|
};
|
|
449
461
|
}
|
|
450
462
|
}
|
|
@@ -460,6 +472,9 @@ Provide:
|
|
|
460
472
|
return this.parseJestOutput(stdout, stderr, file, exitCode);
|
|
461
473
|
case 'mocha':
|
|
462
474
|
return this.parseMochaOutput(stdout, stderr, file, exitCode);
|
|
475
|
+
case 'node':
|
|
476
|
+
case 'node-test':
|
|
477
|
+
return this.parseNodeTestOutput(stdout, stderr, file, exitCode);
|
|
463
478
|
default:
|
|
464
479
|
return this.parseVitestOutput(stdout, stderr, file, exitCode);
|
|
465
480
|
}
|
|
@@ -469,6 +484,47 @@ Provide:
|
|
|
469
484
|
`stdout: ${stdout.slice(0, 500)}\nstderr: ${stderr.slice(0, 500)}`));
|
|
470
485
|
}
|
|
471
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* Parse the TAP or spec summary emitted by Node's built-in test runner.
|
|
489
|
+
*/
|
|
490
|
+
parseNodeTestOutput(stdout, stderr, file, exitCode) {
|
|
491
|
+
const output = `${stdout}\n${stderr}`;
|
|
492
|
+
const summary = new Map();
|
|
493
|
+
for (const match of output.matchAll(/^(?:#|ℹ) (tests|pass|fail|cancelled|skipped|todo) (\d+)\s*$/gm)) {
|
|
494
|
+
summary.set(match[1], Number(match[2]));
|
|
495
|
+
}
|
|
496
|
+
const total = summary.get('tests') ?? 0;
|
|
497
|
+
if (total === 0) {
|
|
498
|
+
return err(new Error(`node:test reported zero tests for ${file}`));
|
|
499
|
+
}
|
|
500
|
+
const passed = summary.get('pass') ?? 0;
|
|
501
|
+
const failed = summary.get('fail') ?? 0;
|
|
502
|
+
const skipped = (summary.get('skipped') ?? 0) +
|
|
503
|
+
(summary.get('cancelled') ?? 0) +
|
|
504
|
+
(summary.get('todo') ?? 0);
|
|
505
|
+
if (exitCode !== 0 && failed === 0) {
|
|
506
|
+
return err(new Error(`node:test exited with code ${exitCode ?? 'unknown'} for ${file}`));
|
|
507
|
+
}
|
|
508
|
+
const failedNames = [
|
|
509
|
+
...Array.from(output.matchAll(/^not ok \d+ - (.+)$/gm), match => match[1].trim()),
|
|
510
|
+
...Array.from(output.matchAll(/^✖ (.+?)(?: \(|$)/gm), match => match[1].trim()),
|
|
511
|
+
];
|
|
512
|
+
const failedTests = Array.from({ length: failed }, (_, index) => ({
|
|
513
|
+
testId: uuidv4(),
|
|
514
|
+
testName: failedNames[index] ?? `node:test failure ${index + 1}`,
|
|
515
|
+
file,
|
|
516
|
+
error: stderr.trim() || failedNames[index] || 'Test failed',
|
|
517
|
+
duration: 0,
|
|
518
|
+
}));
|
|
519
|
+
return ok({
|
|
520
|
+
total,
|
|
521
|
+
passed,
|
|
522
|
+
failed,
|
|
523
|
+
skipped,
|
|
524
|
+
failedTests,
|
|
525
|
+
coverage: undefined,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
472
528
|
/**
|
|
473
529
|
* Parse vitest JSON output
|
|
474
530
|
*/
|
|
@@ -762,8 +818,7 @@ Provide:
|
|
|
762
818
|
return shards;
|
|
763
819
|
}
|
|
764
820
|
async executeWorker(files, _workerIndex, _isolation, request) {
|
|
765
|
-
|
|
766
|
-
return this.aggregateResults(results);
|
|
821
|
+
return this.executeTestFiles(files, request.framework, request.timeout ?? 30000);
|
|
767
822
|
}
|
|
768
823
|
aggregateResults(results) {
|
|
769
824
|
const aggregated = {
|
|
@@ -973,6 +1028,14 @@ Provide:
|
|
|
973
1028
|
statement: result.coverage.statement ?? 0,
|
|
974
1029
|
files: result.fileCoverages?.length ?? 0,
|
|
975
1030
|
}, { persist: true });
|
|
1031
|
+
if (Number.isFinite(result.coverage.line)) {
|
|
1032
|
+
await writeQualityEvidence(this.memory, {
|
|
1033
|
+
coverage: result.coverage.line,
|
|
1034
|
+
}, {
|
|
1035
|
+
measuredAt: new Date().toISOString(),
|
|
1036
|
+
source: 'test-execution coverage',
|
|
1037
|
+
});
|
|
1038
|
+
}
|
|
976
1039
|
// Store per-file coverage via memory.set() (not storeVector) so that
|
|
977
1040
|
// quality-analyzer's getStoredCoverage() can read it with memory.get()
|
|
978
1041
|
if (result.fileCoverages) {
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* 3. Empty test bodies - it('...', () => {}) with no assertions
|
|
9
9
|
* 4. Mirrored assertions - expected values copy-pasted from source literals
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Detection is deterministic (TypeScript parser plus structural checks), with no LLM calls.
|
|
12
12
|
*/
|
|
13
|
-
export type TestQualityIssueType = 'no-source-import' | 'tautological-assertion' | 'empty-test-body' | 'mirrored-assertion';
|
|
13
|
+
export type TestQualityIssueType = 'syntax-error' | 'no-assertions' | 'no-source-import' | 'tautological-assertion' | 'empty-test-body' | 'mirrored-assertion';
|
|
14
14
|
export interface TestQualityIssue {
|
|
15
15
|
type: TestQualityIssueType;
|
|
16
16
|
severity: 'error' | 'warning';
|
|
@@ -35,6 +35,12 @@ export interface TestQualityGateConfig {
|
|
|
35
35
|
/** Minimum score to pass (default: 60) */
|
|
36
36
|
minPassScore: number;
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Return parser errors for generated JavaScript/TypeScript.
|
|
40
|
+
* This is deliberately exported so generation can reject malformed LLM output
|
|
41
|
+
* before replacing a valid deterministic template.
|
|
42
|
+
*/
|
|
43
|
+
export declare function getGeneratedTestSyntaxIssues(testCode: string, sourceFilePath: string): TestQualityIssue[];
|
|
38
44
|
export declare class TestQualityGate {
|
|
39
45
|
private readonly config;
|
|
40
46
|
constructor(config?: Partial<TestQualityGateConfig>);
|
|
@@ -8,8 +8,87 @@
|
|
|
8
8
|
* 3. Empty test bodies - it('...', () => {}) with no assertions
|
|
9
9
|
* 4. Mirrored assertions - expected values copy-pasted from source literals
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* Detection is deterministic (TypeScript parser plus structural checks), with no LLM calls.
|
|
12
12
|
*/
|
|
13
|
+
import ts from 'typescript';
|
|
14
|
+
function scriptKindFor(filePath) {
|
|
15
|
+
if (/\.(?:jsx)$/i.test(filePath))
|
|
16
|
+
return ts.ScriptKind.JSX;
|
|
17
|
+
if (/\.(?:tsx)$/i.test(filePath))
|
|
18
|
+
return ts.ScriptKind.TSX;
|
|
19
|
+
if (/\.(?:js|mjs|cjs)$/i.test(filePath))
|
|
20
|
+
return ts.ScriptKind.JS;
|
|
21
|
+
return ts.ScriptKind.TS;
|
|
22
|
+
}
|
|
23
|
+
function isJavaScriptFamily(filePath) {
|
|
24
|
+
return /\.(?:tsx?|jsx?|mjs|cjs|mts|cts)$/i.test(filePath);
|
|
25
|
+
}
|
|
26
|
+
function parseGeneratedTest(testCode, sourceFilePath) {
|
|
27
|
+
const extension = sourceFilePath.match(/\.(?:tsx?|jsx?|mjs|cjs|mts|cts)$/i)?.[0] ?? '.ts';
|
|
28
|
+
return ts.createSourceFile(`generated.test${extension}`, testCode, ts.ScriptTarget.Latest, true, scriptKindFor(sourceFilePath));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Return parser errors for generated JavaScript/TypeScript.
|
|
32
|
+
* This is deliberately exported so generation can reject malformed LLM output
|
|
33
|
+
* before replacing a valid deterministic template.
|
|
34
|
+
*/
|
|
35
|
+
export function getGeneratedTestSyntaxIssues(testCode, sourceFilePath) {
|
|
36
|
+
if (!isJavaScriptFamily(sourceFilePath))
|
|
37
|
+
return [];
|
|
38
|
+
const diagnostics = ts.transpileModule(testCode, {
|
|
39
|
+
fileName: sourceFilePath,
|
|
40
|
+
reportDiagnostics: true,
|
|
41
|
+
compilerOptions: {
|
|
42
|
+
jsx: ts.JsxEmit.Preserve,
|
|
43
|
+
module: ts.ModuleKind.ESNext,
|
|
44
|
+
target: ts.ScriptTarget.Latest,
|
|
45
|
+
},
|
|
46
|
+
}).diagnostics ?? [];
|
|
47
|
+
return diagnostics.map((diagnostic) => {
|
|
48
|
+
const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
|
|
49
|
+
return {
|
|
50
|
+
type: 'syntax-error',
|
|
51
|
+
severity: 'error',
|
|
52
|
+
line: position ? position.line + 1 : undefined,
|
|
53
|
+
description: `Generated test has invalid syntax: ${ts.flattenDiagnosticMessageText(diagnostic.messageText, ' ')}`,
|
|
54
|
+
suggestion: 'Repair the generated test syntax before accepting or executing it.',
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function hasExecutableAssertion(testCode, sourceFilePath) {
|
|
59
|
+
if (!isJavaScriptFamily(sourceFilePath)) {
|
|
60
|
+
return /\b(?:assert\w*|expect)\s*(?:[.(])/i.test(testCode);
|
|
61
|
+
}
|
|
62
|
+
const sourceFile = parseGeneratedTest(testCode, sourceFilePath);
|
|
63
|
+
let found = false;
|
|
64
|
+
const visit = (node) => {
|
|
65
|
+
if (found)
|
|
66
|
+
return;
|
|
67
|
+
if (ts.isCallExpression(node)) {
|
|
68
|
+
const expression = node.expression;
|
|
69
|
+
if (ts.isIdentifier(expression)) {
|
|
70
|
+
found = expression.text === 'expect' || expression.text === 'assert';
|
|
71
|
+
}
|
|
72
|
+
else if (ts.isPropertyAccessExpression(expression)) {
|
|
73
|
+
let root = expression.expression;
|
|
74
|
+
while (ts.isPropertyAccessExpression(root))
|
|
75
|
+
root = root.expression;
|
|
76
|
+
if (ts.isIdentifier(root) && root.text === 'assert') {
|
|
77
|
+
found = true;
|
|
78
|
+
}
|
|
79
|
+
else if (ts.isIdentifier(root)
|
|
80
|
+
&& root.text === 'expect'
|
|
81
|
+
&& expression.name.text !== 'assertions'
|
|
82
|
+
&& expression.name.text !== 'hasAssertions') {
|
|
83
|
+
found = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
ts.forEachChild(node, visit);
|
|
88
|
+
};
|
|
89
|
+
visit(sourceFile);
|
|
90
|
+
return found;
|
|
91
|
+
}
|
|
13
92
|
const DEFAULT_CONFIG = {
|
|
14
93
|
checkSourceImports: true,
|
|
15
94
|
checkTautologicalAssertions: true,
|
|
@@ -34,7 +113,15 @@ export class TestQualityGate {
|
|
|
34
113
|
* @returns Gate result with pass/fail, issues, and score
|
|
35
114
|
*/
|
|
36
115
|
validate(testCode, sourceFilePath, sourceCode) {
|
|
37
|
-
const issues =
|
|
116
|
+
const issues = getGeneratedTestSyntaxIssues(testCode, sourceFilePath);
|
|
117
|
+
if (!hasExecutableAssertion(testCode, sourceFilePath)) {
|
|
118
|
+
issues.push({
|
|
119
|
+
type: 'no-assertions',
|
|
120
|
+
severity: 'error',
|
|
121
|
+
description: 'Generated test contains no executable assertions.',
|
|
122
|
+
suggestion: 'Add at least one assertion that observes behavior from the source under test.',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
38
125
|
if (this.config.checkSourceImports) {
|
|
39
126
|
issues.push(...this.detectMissingSourceImports(testCode, sourceFilePath));
|
|
40
127
|
}
|
|
@@ -47,8 +134,10 @@ export class TestQualityGate {
|
|
|
47
134
|
if (this.config.checkMirroredAssertions && sourceCode) {
|
|
48
135
|
issues.push(...this.detectMirroredAssertions(testCode, sourceCode));
|
|
49
136
|
}
|
|
50
|
-
const
|
|
51
|
-
const
|
|
137
|
+
const mechanicallyInvalid = issues.some(issue => issue.type === 'syntax-error' || issue.type === 'no-assertions');
|
|
138
|
+
const hasError = issues.some(issue => issue.severity === 'error');
|
|
139
|
+
const score = mechanicallyInvalid ? 0 : this.calculateScore(issues);
|
|
140
|
+
const passed = !hasError && score >= this.config.minPassScore;
|
|
52
141
|
return { passed, issues, score };
|
|
53
142
|
}
|
|
54
143
|
// ============================================================================
|
|
@@ -157,21 +157,6 @@ export class BaseTestGenerator {
|
|
|
157
157
|
assertion: 'expect(action).toThrow();',
|
|
158
158
|
});
|
|
159
159
|
}
|
|
160
|
-
else {
|
|
161
|
-
// Function has no explicit throw — but may still crash on property access.
|
|
162
|
-
// Use try-catch pattern that accepts either behavior.
|
|
163
|
-
const undefinedCall = fn.isAsync
|
|
164
|
-
? `await ${fn.name}(${paramsWithUndefined})`
|
|
165
|
-
: `${fn.name}(${paramsWithUndefined})`;
|
|
166
|
-
testCases.push({
|
|
167
|
-
description: `should handle undefined ${param.name}`,
|
|
168
|
-
type: 'edge-case',
|
|
169
|
-
action: fn.isAsync
|
|
170
|
-
? `let threw = false;\n try {\n await ${fn.name}(${paramsWithUndefined});\n } catch (e) {\n threw = true;\n expect(e).toBeInstanceOf(Error);\n }`
|
|
171
|
-
: `let threw = false;\n try {\n ${fn.name}(${paramsWithUndefined});\n } catch (e) {\n threw = true;\n expect(e).toBeInstanceOf(Error);\n }`,
|
|
172
|
-
assertion: `expect(true).toBe(true); // function either handles undefined or throws TypeError`,
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
160
|
}
|
|
176
161
|
// Type-specific boundary tests
|
|
177
162
|
testCases.push(...this.generateBoundaryTestCases(fn, param));
|