agentic-qe 3.13.0 → 3.13.2
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/.agents/skills/aqe-plan-quality/SKILL.md +25 -0
- package/.agents/skills/aqe-plan-quality/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-plan-quality/references/qe-routing.md +22 -0
- package/.agents/skills/aqe-review-quality/SKILL.md +24 -0
- package/.agents/skills/aqe-review-quality/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-review-quality/references/quality-gates.md +20 -0
- package/.agents/skills/aqe-test-change/SKILL.md +26 -0
- package/.agents/skills/aqe-test-change/agents/openai.yaml +4 -0
- package/.agents/skills/aqe-test-change/references/test-specialties.md +23 -0
- package/.claude/helpers/ruflo-hook.cjs +5 -1
- package/.claude/skills/skills-manifest.json +1 -1
- package/.codex/hooks/aqe-codex-hook.cjs +69 -0
- package/.codex/hooks/ruflo-codex-hook.cjs +94 -0
- package/.codex/hooks.json +169 -0
- package/CHANGELOG.md +123 -0
- package/assets/skills/skills-manifest.json +1 -1
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-I4SNWMCM.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-ACX2DK7Y.js → agent-booster-wasm-PZYYTKSS.js} +2 -2
- package/dist/cli/chunks/{agent-handler-B45WP4ZJ.js → agent-handler-DNN7GXUN.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-QQLZDE56.js → agent-memory-branch-LVCBBCQY.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-WI47XKXI.js +2 -0
- package/dist/cli/chunks/{arena-SDB7723R.js → arena-422HSTPE.js} +2 -2
- package/dist/cli/chunks/{arena-G3IKZAG5.js → arena-OCEOLMCH.js} +4 -4
- package/dist/cli/chunks/{audit-GY46XUZA.js → audit-5O45K34M.js} +3 -3
- package/dist/cli/chunks/base-VJ6VDLD7.js +2 -0
- package/dist/cli/chunks/{hnswlib-node-RJPBJU2Q.js → better-sqlite3-Y36THYK2.js} +2 -2
- package/dist/cli/chunks/{brain-handler-347CYMPN.js → brain-handler-7VHXYN3P.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-Z3ULBFSM.js → branch-enumerator-PZKOD6S6.js} +2 -2
- package/dist/cli/chunks/{browser-OYEIHD7F.js → browser-M74UO4WJ.js} +2 -2
- package/dist/cli/chunks/browser-workflow-WRYHQQDU.js +2 -0
- package/dist/cli/chunks/{chunk-RVJPWRV6.js → chunk-24S5IUSI.js} +2 -2
- package/dist/cli/chunks/{chunk-3NOCK6ED.js → chunk-2DG44UZ5.js} +2 -2
- package/dist/cli/chunks/{chunk-34PEINFS.js → chunk-2QJPAQE5.js} +2 -2
- package/dist/cli/chunks/{chunk-SHCTEXNH.js → chunk-4DKL4H5L.js} +2 -2
- package/dist/cli/chunks/{chunk-A4QLGPYO.js → chunk-4FYTWD4Q.js} +2 -2
- package/dist/cli/chunks/{chunk-YFGAHNCG.js → chunk-4HFNY3Z2.js} +3 -3
- package/dist/cli/chunks/{chunk-RVRBTOWX.js → chunk-4PM5VORA.js} +2 -2
- package/dist/cli/chunks/{chunk-QWYISZTN.js → chunk-4SFOQSXU.js} +2 -2
- package/dist/cli/chunks/{chunk-RSFIOR2I.js → chunk-4STE6VLR.js} +87 -87
- package/dist/cli/chunks/{chunk-54MFKCLT.js → chunk-54BCLRRJ.js} +2 -2
- package/dist/cli/chunks/{chunk-IYDYJ33J.js → chunk-5AAG7JTB.js} +2 -2
- package/dist/cli/chunks/{chunk-TVMFH5N2.js → chunk-5EFNZEOB.js} +2 -2
- package/dist/cli/chunks/{chunk-GUEZQOHL.js → chunk-5GGGZYFA.js} +1 -1
- package/dist/cli/chunks/{chunk-5KAT6WBQ.js → chunk-5KMBZTDI.js} +2 -2
- package/dist/cli/chunks/{chunk-ANYYTWOQ.js → chunk-5XYVRTI6.js} +2 -2
- package/dist/cli/chunks/{chunk-ANIDFJCT.js → chunk-62D27BDO.js} +3 -3
- package/dist/cli/chunks/{chunk-SNTUKW4Q.js → chunk-6DMB6WK5.js} +2 -2
- package/dist/cli/chunks/{chunk-ZCFZ4USU.js → chunk-6R7TX5L4.js} +1 -1
- package/dist/cli/chunks/chunk-6UGYFYS4.js +2 -0
- package/dist/cli/chunks/chunk-6XHDH3IJ.js +3 -0
- package/dist/cli/chunks/{chunk-IHQTXJAQ.js → chunk-73HALJY5.js} +1 -1
- package/dist/cli/chunks/{chunk-7YXT6BXN.js → chunk-7TCVVVFA.js} +3 -3
- package/dist/cli/chunks/{chunk-RJZRWVL4.js → chunk-A2OD5Z4B.js} +1 -1
- package/dist/cli/chunks/{chunk-ES7WCYOU.js → chunk-AJ7A52GF.js} +1 -1
- package/dist/cli/chunks/{chunk-QCEW4ZDW.js → chunk-AP2BBV2D.js} +2 -2
- package/dist/cli/chunks/{chunk-FQLWQWRU.js → chunk-AS2HVJ42.js} +3 -3
- package/dist/cli/chunks/{chunk-7UNY32PU.js → chunk-ASIGTVFQ.js} +1 -1
- package/dist/cli/chunks/{chunk-EECM5XKY.js → chunk-B7KZMPF2.js} +1 -1
- package/dist/cli/chunks/{chunk-Z6QCOZ2H.js → chunk-BFKXHXWW.js} +2 -2
- package/dist/cli/chunks/{chunk-VC6EXDGY.js → chunk-BO2RBAPF.js} +2 -2
- package/dist/cli/chunks/{chunk-OXXMVQDF.js → chunk-BSQ32ZS5.js} +2 -2
- package/dist/cli/chunks/{chunk-WRYT4HTZ.js → chunk-CKTFKA7Q.js} +2 -2
- package/dist/cli/chunks/{chunk-QQB55ZJJ.js → chunk-CLBBFKXV.js} +2 -2
- package/dist/cli/chunks/{chunk-5FLTZ3KT.js → chunk-COOMXCCP.js} +2 -2
- package/dist/cli/chunks/{chunk-DYUC7WFA.js → chunk-DAHNHVND.js} +1 -1
- package/dist/cli/chunks/{chunk-6AOBLBR4.js → chunk-DCQQJLUY.js} +2 -2
- package/dist/cli/chunks/{chunk-LBE2P6UC.js → chunk-DIPOFCBX.js} +2 -2
- package/dist/cli/chunks/{chunk-EFRESRLB.js → chunk-DL2HDULJ.js} +5 -5
- package/dist/cli/chunks/{chunk-YRQLVGCI.js → chunk-DQXSDWRP.js} +2 -2
- package/dist/cli/chunks/{chunk-QI4CGJNK.js → chunk-E6JJ4ZRQ.js} +1 -1
- package/dist/cli/chunks/{chunk-KUA4HHU6.js → chunk-E6PYV3DB.js} +2 -2
- package/dist/cli/chunks/{chunk-ZJG6N2OK.js → chunk-EABGQVTV.js} +1 -1
- package/dist/cli/chunks/{chunk-U2SW6KK5.js → chunk-EFHMS7TJ.js} +2 -2
- package/dist/cli/chunks/{chunk-CWUBOLKY.js → chunk-ELVUERQW.js} +2 -2
- package/dist/cli/chunks/{chunk-A7GLWWSE.js → chunk-EU7NUUL6.js} +1 -1
- package/dist/cli/chunks/{chunk-3UHEZ5HZ.js → chunk-F6UMLI5Y.js} +2 -2
- package/dist/cli/chunks/{chunk-TZPKTRJB.js → chunk-FECBWGCA.js} +2 -2
- package/dist/cli/chunks/{chunk-OETDMOOE.js → chunk-FFMUTX26.js} +1 -1
- package/dist/cli/chunks/{chunk-VLNPJAVH.js → chunk-FJ2L6P7O.js} +1 -1
- package/dist/cli/chunks/{chunk-2DIT5AUU.js → chunk-FMYNKZ2S.js} +2 -2
- package/dist/cli/chunks/{chunk-L4LLA5U7.js → chunk-FXXXLDB3.js} +1 -1
- package/dist/cli/chunks/{chunk-D3MPV5G7.js → chunk-FZEWEG6Q.js} +2 -2
- package/dist/cli/chunks/{chunk-BGYLNCL6.js → chunk-G4LZ5SBC.js} +2 -2
- package/dist/cli/chunks/{chunk-J3L52EA4.js → chunk-GHJRLC3C.js} +5 -5
- package/dist/cli/chunks/{chunk-3JVUWKCO.js → chunk-GKKD22CC.js} +2 -2
- package/dist/cli/chunks/{chunk-32ZGV4Q4.js → chunk-GMKJWOXZ.js} +1 -1
- package/dist/cli/chunks/chunk-GMKQJEKX.js +2 -0
- package/dist/cli/chunks/{chunk-3GSYD5SL.js → chunk-GZ775E5O.js} +2 -2
- package/dist/cli/chunks/{chunk-GTUFX7AR.js → chunk-H6C2YTPX.js} +2 -2
- package/dist/cli/chunks/{chunk-UIPPJKON.js → chunk-HANBJ37Z.js} +2 -2
- package/dist/cli/chunks/{chunk-ZOXWASCC.js → chunk-HANJESCY.js} +2 -2
- package/dist/cli/chunks/{chunk-JPIBPKBP.js → chunk-HD6PZHLC.js} +3 -3
- package/dist/cli/chunks/{chunk-FQY3UTGA.js → chunk-HHUKHEW5.js} +2 -2
- package/dist/cli/chunks/{chunk-W5YEIHIO.js → chunk-HQCJYUKC.js} +2 -2
- package/dist/cli/chunks/{chunk-CYL2FV23.js → chunk-IIZ3HBPV.js} +2 -2
- package/dist/cli/chunks/{chunk-HTPM3URI.js → chunk-IV77BQ2R.js} +2 -2
- package/dist/cli/chunks/{chunk-THBTN7XB.js → chunk-J722Z7VO.js} +2 -2
- package/dist/cli/chunks/{chunk-5EIOQCGN.js → chunk-JDRYENTD.js} +2 -2
- package/dist/cli/chunks/{chunk-NQNKKVNO.js → chunk-JKVUSXT4.js} +3 -3
- package/dist/cli/chunks/{chunk-CQFT7H3F.js → chunk-JMRUHQEL.js} +2 -2
- package/dist/cli/chunks/{chunk-PERJO2DY.js → chunk-JPO4AC5Q.js} +1 -1
- package/dist/cli/chunks/{chunk-KSYLRM4Q.js → chunk-JPPHM3I6.js} +2 -2
- package/dist/cli/chunks/{chunk-56WZFXTQ.js → chunk-K3MNTU4O.js} +2 -2
- package/dist/cli/chunks/{chunk-CPH5JP4L.js → chunk-K47EWX3M.js} +1 -1
- package/dist/cli/chunks/{chunk-7DMXCCSD.js → chunk-KAHMXURL.js} +1 -1
- package/dist/cli/chunks/{chunk-UNIBND6A.js → chunk-KHVW6DQS.js} +1 -1
- package/dist/cli/chunks/{chunk-RLCWR7TS.js → chunk-KKPWS3XJ.js} +98 -88
- package/dist/cli/chunks/chunk-KRRGOJ6K.js +2 -0
- package/dist/cli/chunks/chunk-LEOSNZR2.js +2 -0
- package/dist/cli/chunks/{chunk-TNRIGQ6U.js → chunk-LG6UUM55.js} +2 -2
- package/dist/cli/chunks/{chunk-HOKON5EL.js → chunk-LJWIBYTR.js} +2 -2
- package/dist/cli/chunks/{chunk-N7VOOI3U.js → chunk-LQDQTLWV.js} +2 -2
- package/dist/cli/chunks/{chunk-2NRZYQSF.js → chunk-LXYVWAFN.js} +2 -2
- package/dist/cli/chunks/{chunk-YPTGE5NJ.js → chunk-LZNJ7HXB.js} +2 -2
- package/dist/cli/chunks/{chunk-6SXKCIN5.js → chunk-M4JZOCV3.js} +1 -1
- package/dist/cli/chunks/{chunk-UMG5URNV.js → chunk-MBTVAIFF.js} +1 -1
- package/dist/cli/chunks/{chunk-N5MMBA35.js → chunk-MNDPSIEI.js} +1 -1
- package/dist/cli/chunks/{chunk-L4S722JD.js → chunk-MUSLUG6Y.js} +1 -1
- package/dist/cli/chunks/{chunk-VLBV2VL3.js → chunk-MVJ5UQI3.js} +1 -1
- package/dist/cli/chunks/{chunk-XFCWYQHW.js → chunk-N2AGOQCL.js} +2 -2
- package/dist/cli/chunks/{chunk-KVL63BSU.js → chunk-N4O2RWSL.js} +1 -1
- package/dist/cli/chunks/{chunk-L2SFGFE6.js → chunk-NBRKZOPM.js} +1 -1
- package/dist/cli/chunks/{chunk-NETN3OUG.js → chunk-NIE3SGZM.js} +1 -1
- package/dist/cli/chunks/{chunk-LOXVVMS4.js → chunk-NNIKJZA4.js} +3 -3
- package/dist/cli/chunks/{chunk-5ICQL42E.js → chunk-NTKIDOIW.js} +2 -2
- package/dist/cli/chunks/{chunk-Q7PBGNUD.js → chunk-ODE7Z667.js} +1 -1
- package/dist/cli/chunks/{chunk-K5N6SLHO.js → chunk-OYWZYG6Q.js} +1 -1
- package/dist/cli/chunks/{chunk-CFVEDUTW.js → chunk-P33EORZZ.js} +2 -2
- package/dist/cli/chunks/{chunk-R3GEXYO4.js → chunk-PILZKQX7.js} +2 -2
- package/dist/cli/chunks/{chunk-ZJIX5FGQ.js → chunk-PJOH5Z5I.js} +2 -2
- package/dist/cli/chunks/{chunk-JGM6XCCP.js → chunk-PNQWEOE2.js} +1 -1
- package/dist/cli/chunks/{chunk-XKFE3FLI.js → chunk-PRQPUOSH.js} +2 -2
- package/dist/cli/chunks/{chunk-LWYLW7RX.js → chunk-PT6NTWGT.js} +2 -2
- package/dist/cli/chunks/{chunk-FBBZHATF.js → chunk-Q45FBGVV.js} +1 -1
- package/dist/cli/chunks/{chunk-SRQ3CPJE.js → chunk-Q625ISQI.js} +4 -4
- package/dist/cli/chunks/{chunk-BOVH6WSM.js → chunk-QS6TI7NR.js} +2 -2
- package/dist/cli/chunks/{chunk-4BDLD7V2.js → chunk-QVD3LU27.js} +1 -1
- package/dist/cli/chunks/{chunk-ZLXBNNNT.js → chunk-QZACODX6.js} +2 -2
- package/dist/cli/chunks/{chunk-NUQBJGGF.js → chunk-REBNPQI7.js} +2 -2
- package/dist/cli/chunks/{chunk-FAQLI3P5.js → chunk-RF2DMPX2.js} +2 -2
- package/dist/cli/chunks/{chunk-2VQVEQS4.js → chunk-RI2V2U2N.js} +2 -2
- package/dist/cli/chunks/{chunk-GJMZR7WU.js → chunk-RJYAUJDC.js} +3 -3
- package/dist/cli/chunks/{chunk-KZTBNDNE.js → chunk-RWHHOQIC.js} +1 -1
- package/dist/cli/chunks/{chunk-ZEIG5IQ4.js → chunk-RWUK5VMZ.js} +2 -2
- package/dist/cli/chunks/{chunk-E3B5XTXJ.js → chunk-SOOI2HJB.js} +1 -1
- package/dist/cli/chunks/{chunk-IPHLXAMX.js → chunk-T2XXTEZV.js} +2 -2
- package/dist/cli/chunks/{chunk-USMDIIHY.js → chunk-T55XIENI.js} +2 -2
- package/dist/cli/chunks/{chunk-VSNRPMAZ.js → chunk-T726SRYP.js} +2 -2
- package/dist/cli/chunks/{chunk-RDU4WTV2.js → chunk-TLG56A27.js} +2 -2
- package/dist/cli/chunks/{chunk-FUU32QY5.js → chunk-TTWWCWAR.js} +2 -2
- package/dist/cli/chunks/{chunk-LXPB7H2P.js → chunk-TVWX7NYD.js} +1 -1
- package/dist/cli/chunks/{chunk-G5DFYX3J.js → chunk-U2FCUBBW.js} +2 -2
- package/dist/cli/chunks/{chunk-DRIJYTSK.js → chunk-UIQVVS7K.js} +2 -2
- package/dist/cli/chunks/{chunk-6DTOGSDV.js → chunk-UPGJZA3D.js} +4 -4
- package/dist/cli/chunks/{chunk-3K4SF57Q.js → chunk-UVLWT6QM.js} +1 -1
- package/dist/cli/chunks/{chunk-FL3BM54K.js → chunk-VKU5BUUC.js} +1 -1
- package/dist/cli/chunks/{chunk-AO7AHX6K.js → chunk-VOYUCJLK.js} +2 -2
- package/dist/cli/chunks/{chunk-BCKTBGDM.js → chunk-WMK2ZNLM.js} +3 -3
- package/dist/cli/chunks/{chunk-4BESADKE.js → chunk-WTSVP6OK.js} +2 -2
- package/dist/cli/chunks/{chunk-MBCGI3M2.js → chunk-XS2S3ECA.js} +5 -5
- package/dist/cli/chunks/chunk-XXQLFPIK.js +2 -0
- package/dist/cli/chunks/{chunk-HL2QMM4M.js → chunk-XZOTFJHU.js} +2 -2
- package/dist/cli/chunks/{chunk-QTU3CVOB.js → chunk-YTHUTBBH.js} +2 -2
- package/dist/cli/chunks/{chunk-BUGWPTMF.js → chunk-YWJ2GPD4.js} +2 -2
- package/dist/cli/chunks/{chunk-GFBLWFRV.js → chunk-YXTDCP6H.js} +1 -1
- package/dist/cli/chunks/{chunk-TZ73SXQ5.js → chunk-YZUMCXH6.js} +1 -1
- package/dist/cli/chunks/{chunk-VHYMSZNF.js → chunk-ZIT5VF43.js} +2 -2
- package/dist/cli/chunks/{chunk-IZRLIWFN.js → chunk-ZY5FB3JV.js} +2 -2
- package/dist/cli/chunks/{ci-74ZUCO5V.js → ci-EOFZKCSH.js} +2 -2
- package/dist/cli/chunks/{ci-output-HD6IZNJA.js → ci-output-TAJFQWDP.js} +2 -2
- package/dist/cli/chunks/{circuit-breaker-USZVMA42.js → circuit-breaker-QA7YJ3IF.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-S4XKNCD5.js → claude-flow-setup-4RNAIALK.js} +2 -2
- package/dist/cli/chunks/client-N2WAM5IK.js +2 -0
- package/dist/cli/chunks/{cline-installer-6EW4CHAR.js → cline-installer-K25NUUA4.js} +2 -2
- package/dist/cli/chunks/{code-TOLWD2XL.js → code-JM4D3I2W.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-UA4QQ7B3.js → code-index-extractor-6B6TJ2B5.js} +2 -2
- package/dist/cli/chunks/codex-installer-GRUENCIO.js +10 -0
- package/dist/cli/chunks/{completions-KVUMQQ4K.js → completions-LADTXGCC.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-DFH6LMK2.js → complexity-analyzer-IQITOJH5.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-LYDQSAU7.js → continuedev-installer-H6NAXFZK.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-7USXLZHZ.js → copilot-installer-W7HCQKOS.js} +2 -2
- package/dist/cli/chunks/core-handlers-VSX474R3.js +2 -0
- package/dist/cli/chunks/{cost-tracker-JBDIUMKZ.js → cost-tracker-MC7KEENQ.js} +2 -2
- package/dist/cli/chunks/{coverage-RGO3K357.js → coverage-NOOKPFYQ.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-VNE7QKX4.js +2 -0
- package/dist/cli/chunks/{cursor-installer-YEZGD37F.js → cursor-installer-GOZ64GZJ.js} +2 -2
- package/dist/cli/chunks/{daemon-FVETQ3LL.js → daemon-G4ABQMFJ.js} +3 -3
- package/dist/cli/chunks/{daemon-LPEXHNYG.js → daemon-V23WTCJJ.js} +4 -4
- package/dist/cli/chunks/{dag-attention-scheduler-UKYE2FII.js → dag-attention-scheduler-YKOO6ZWL.js} +2 -2
- package/dist/cli/chunks/{detect-WBG5P7ER.js → detect-SNEMKQGJ.js} +2 -2
- package/dist/cli/chunks/{dist-node-YW6YRBCU.js → dist-node-VBNEM6K6.js} +2 -2
- package/dist/cli/chunks/{domain-handler-HH7J4A32.js → domain-handler-2G5XEERC.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-V34GXD5I.js → domain-transfer-HSEUUM7E.js} +2 -2
- package/dist/cli/chunks/dream-A5LVJU7T.js +2 -0
- package/dist/cli/chunks/{embed-and-insert-pattern-WYLRS3CL.js → embed-and-insert-pattern-H6MU5HK4.js} +2 -2
- package/dist/cli/chunks/{eval-EIMVXY5J.js → eval-XYVDJXJF.js} +2 -2
- package/dist/cli/chunks/{experience-capture-middleware-QMZHRUKM.js → experience-capture-middleware-BZQJVXTE.js} +3 -3
- package/dist/cli/chunks/{fast-paths-NHLW6XS6.js → fast-paths-76WWBJ4H.js} +2 -2
- package/dist/cli/chunks/{feature-flags-NE3MBL3P.js → feature-flags-7E5YZ4P5.js} +2 -2
- package/dist/cli/chunks/{feature-flags-N3UHMSZ3.js → feature-flags-SCQ35J6M.js} +2 -2
- package/dist/cli/chunks/{file-discovery-SI44X4YS.js → file-discovery-LU5MAXWA.js} +2 -2
- package/dist/cli/chunks/{fleet-MMYUXRRM.js → fleet-M3TH65SV.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-RLYXYU2Q.js → gnn-wrapper-OYUJEJD2.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-6EDRUYLV.js → heartbeat-handler-II4NSOXK.js} +4 -4
- package/dist/cli/chunks/heartbeat-scheduler-CFZ6DNQY.js +2 -0
- package/dist/cli/chunks/hnsw-adapter-I4Y2T4HO.js +2 -0
- package/dist/cli/chunks/hnsw-index-SBR5VYGN.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-RVM7EAIH.js → hnsw-legacy-bridge-322R2UAB.js} +2 -2
- package/dist/cli/chunks/{better-sqlite3-DUZ6FFAH.js → hnswlib-node-OVLAHTPU.js} +2 -2
- package/dist/cli/chunks/{hooks-ZF4VKHEO.js → hooks-2A27XCUJ.js} +37 -37
- package/dist/cli/chunks/hybrid-router-E6YM74NQ.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-YWS66PGO.js → hypergraph-engine-ERA527UR.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-OQHVRPWB.js → hypergraph-handler-7XL4OL6W.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-GHYFSSMJ.js +2 -0
- package/dist/cli/chunks/{init-handler-YW74YF2V.js → init-handler-WN6KQ5WY.js} +6 -6
- package/dist/cli/chunks/init-wizard-KAN5KOGD.js +2 -0
- package/dist/cli/chunks/kernel-LET4HEEF.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-APWB2GMA.js → kilocode-installer-5UCCFZ7V.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-DICKFVNC.js → kiro-installer-77DPEP3K.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-P3UJWNQS.js +2 -0
- package/dist/cli/chunks/{learning-MXHNYW5D.js → learning-A5GKUD73.js} +3 -3
- package/dist/cli/chunks/{llm-router-LTFIX7NY.js → llm-router-SINJNEGP.js} +4 -4
- package/dist/cli/chunks/llm-router-service-BOBENURJ.js +2 -0
- package/dist/cli/chunks/{load-JUMIQ4LZ.js → load-Q56GLXHJ.js} +2 -2
- package/dist/cli/chunks/load-test-4VDCVB7S.js +2 -0
- package/dist/cli/chunks/{mcp-WHIARJGO.js → mcp-VBDU2WLY.js} +2 -2
- package/dist/cli/chunks/{memory-KAHS6Z5A.js → memory-IGWBRDIT.js} +5 -5
- package/dist/cli/chunks/memory-backend-RRFAYQYS.js +2 -0
- package/dist/cli/chunks/{memory-handlers-DG3RRXB6.js → memory-handlers-IITHQ7KV.js} +2 -2
- package/dist/cli/chunks/{multi-model-executor-E3Y2RHMX.js → multi-model-executor-2QUEY4CC.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-3RKGNGGE.js → opencode-installer-FZJ5N2B3.js} +2 -2
- package/dist/cli/chunks/{orchestrator-TXITUKWD.js → orchestrator-BGLDS47V.js} +5 -5
- package/dist/cli/chunks/pattern-null-store-V7DEZEF2.js +2 -0
- package/dist/cli/chunks/{pattern-usage-recorder-EE2BUFZT.js → pattern-usage-recorder-4MFN4WKV.js} +2 -2
- package/dist/cli/chunks/{pipeline-AXTT6KZB.js → pipeline-GZHAORGP.js} +2 -2
- package/dist/cli/chunks/{platform-TICPVKE2.js → platform-TZEX4YZQ.js} +2 -2
- package/dist/cli/chunks/{plugin-VQKNV3EM.js → plugin-VEYUFCNY.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-6GY5YY7D.js → prime-radiant-advanced-wasm-OA5DLXJJ.js} +2 -2
- package/dist/cli/chunks/protocol-executor-I3C2ZETP.js +2 -0
- package/dist/cli/chunks/{protocol-handler-YFWDR7UZ.js → protocol-handler-MVJ5N4X5.js} +2 -2
- package/dist/cli/chunks/{prove-FUMRCXAA.js → prove-VKF7YCUA.js} +2 -2
- package/dist/cli/chunks/provider-manager-HB4YVQDI.js +2 -0
- package/dist/cli/chunks/qe-reasoning-bank-RDLBAXJY.js +2 -0
- package/dist/cli/chunks/{quality-2APISBW5.js → quality-NLB5LVGM.js} +2 -2
- package/dist/cli/chunks/{quality-gate-MCC3E5TM.js → quality-gate-OM6A7FQM.js} +3 -3
- package/dist/cli/chunks/queen-coordinator-QRWRNUDR.js +2 -0
- package/dist/cli/chunks/{real-embeddings-CC5TNOTI.js → real-embeddings-NONEKGAV.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-YAHTEVPI.js → roocode-installer-ORXQQO3F.js} +2 -2
- package/dist/cli/chunks/router-WDF7KV4M.js +2 -0
- package/dist/cli/chunks/routing-feedback-DHYB4ZNL.js +2 -0
- package/dist/cli/chunks/{routing-handler-6NQBW4TQ.js → routing-handler-LGMIBVDS.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-ZHXLHUPG.js → ruvector-commands-4GZMU4BZ.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-5KF2DGCW.js → rvf-dual-writer-45HKI22F.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-BBU57BGF.js → rvf-migration-adapter-RHYIXI3I.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-VN4VRZA4.js → rvf-migration-coordinator-ANTAYKNN.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-7W53TYTH.js +2 -0
- package/dist/cli/chunks/{rvf-store-integrity-XCY2XQZA.js → rvf-store-integrity-CPQUTFST.js} +2 -2
- package/dist/cli/chunks/safe-db-4HBFO7OQ.js +2 -0
- package/dist/cli/chunks/schedule-M2OSBJZM.js +2 -0
- package/dist/cli/chunks/scheduler-JWV5MSGE.js +2 -0
- package/dist/cli/chunks/{security-PYP4H3KN.js → security-BM6LMCBI.js} +3 -3
- package/dist/cli/chunks/{shared-rvf-adapter-3CJHRNX6.js → shared-rvf-adapter-3HGARKJX.js} +2 -2
- package/dist/cli/chunks/{shared-rvf-dual-writer-MKSLKWDI.js → shared-rvf-dual-writer-UQ4O46ZI.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-QA4JRQZ2.js +2 -0
- package/dist/cli/chunks/{status-handler-VYIZ3VJF.js → status-handler-TGRAM5PC.js} +2 -2
- package/dist/cli/chunks/{structural-health-MVV4OWXP.js → structural-health-RXETMBB3.js} +2 -2
- package/dist/cli/chunks/{sync-VNX6L3TI.js → sync-B4KEYFCP.js} +2 -2
- package/dist/cli/chunks/{sync-G47OYIQ3.js → sync-JTBZIACA.js} +2 -2
- package/dist/cli/chunks/{task-handler-GOWF2GEH.js → task-handler-D7VXHWPG.js} +2 -2
- package/dist/cli/chunks/{task-handlers-J2WC6J37.js → task-handlers-XF6VVPTR.js} +3 -3
- package/dist/cli/chunks/{test-DMCJ3BXS.js → test-BKEIMBSX.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-TRFHHKFM.js → test-scheduling-A4OHR7KW.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-KEQ7AHFF.js → token-bootstrap-LIDDAOAK.js} +2 -2
- package/dist/cli/chunks/{token-usage-B54FOFOF.js → token-usage-BJUFIU4V.js} +2 -2
- package/dist/cli/chunks/{transformers-IACZG7IV.js → transformers-YYUQCGMV.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-N7H4X37E.js → tree-sitter-wasm-parser-DFXYTJ23.js} +2 -2
- package/dist/cli/chunks/{types-B3SHT4OD.js → types-Z75HK5HH.js} +2 -2
- package/dist/cli/chunks/unified-memory-BEUZQTTC.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-FHLSAEX4.js +2 -0
- package/dist/cli/chunks/unified-persistence-TVEQGCSB.js +2 -0
- package/dist/cli/chunks/{upgrade-A2PQ5EWK.js → upgrade-NETNZZH3.js} +2 -2
- package/dist/cli/chunks/{validate-UXV7UQUT.js → validate-U2WQ7P6T.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-MMBU4FPP.js → validate-swarm-DKD7H2E3.js} +2 -2
- package/dist/cli/chunks/{vibium-R4GUVADA.js → vibium-FOQ73JBW.js} +2 -2
- package/dist/cli/chunks/visual-security-AYV46OUO.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-MP6E6CJB.js → web-tree-sitter-PQXWMQO6.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-Z6BWMUUO.js → windsurf-installer-CTFSFOBX.js} +2 -2
- package/dist/cli/chunks/{witness-chain-EFLTABBA.js → witness-chain-NCRHNFQM.js} +2 -2
- package/dist/cli/chunks/witness-chain-RU356H6R.js +2 -0
- package/dist/cli/chunks/{witness-key-manager-PN36TV43.js → witness-key-manager-WGCSSB23.js} +2 -2
- package/dist/cli/chunks/{workflow-A2AX3RJU.js → workflow-FE5QGP2U.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-N2DQTC3X.js +2 -0
- package/dist/cli/chunks/{wrappers-NA6FHA63.js → wrappers-AHL5K2LO.js} +2 -2
- package/dist/cli/commands/hooks-handlers/hooks-shared.d.ts +9 -0
- package/dist/cli/commands/hooks-handlers/hooks-shared.js +38 -0
- package/dist/cli/commands/hooks.d.ts +2 -2
- package/dist/cli/commands/hooks.js +8 -2
- package/dist/cli/handlers/init-handler.js +1 -1
- package/dist/coordination/handlers/coverage-collection.d.ts +161 -0
- package/dist/coordination/handlers/coverage-collection.js +643 -0
- package/dist/coordination/handlers/coverage-handlers.js +199 -146
- package/dist/coordination/handlers/handler-types.d.ts +6 -1
- package/dist/coordination/handlers/handler-utils.js +10 -3
- package/dist/coordination/handlers/security-handlers.js +17 -2
- package/dist/coordination/handlers/test-execution-handlers.js +16 -1
- package/dist/coordination/queen-coordinator.js +4 -3
- package/dist/coordination/result-saver.js +119 -97
- package/dist/coordination/task-executor.d.ts +26 -1
- package/dist/coordination/task-executor.js +52 -4
- package/dist/domains/code-intelligence/services/knowledge-graph.js +8 -0
- package/dist/domains/coverage-analysis/services/coverage-analyzer.js +4 -0
- package/dist/domains/coverage-analysis/services/gap-detector.js +4 -0
- package/dist/domains/defect-intelligence/services/defect-predictor.js +4 -0
- package/dist/domains/defect-intelligence/services/root-cause-analyzer.js +4 -0
- package/dist/domains/quality-assessment/services/deployment-advisor.js +4 -0
- package/dist/domains/quality-assessment/services/quality-analyzer.js +4 -0
- package/dist/domains/security-compliance/services/scanners/sast-scanner.js +4 -0
- package/dist/domains/test-generation/index.js +17 -2
- package/dist/domains/test-generation/services/test-generator.js +31 -9
- package/dist/init/codex-installer.d.ts +13 -0
- package/dist/init/codex-installer.js +122 -1
- package/dist/init/phases/09-assets.js +4 -0
- package/dist/init/phases/phase-interface.d.ts +1 -1
- package/dist/integrations/ruvector/rvf-store-integrity.js +5 -1
- package/dist/integrations/ruvector/shared-rvf-adapter.js +5 -5
- package/dist/learning/real-embeddings.js +15 -1
- package/dist/mcp/bundle.js +429 -419
- package/dist/mcp/handlers/domain-handler-configs.js +79 -14
- package/dist/mcp/types.d.ts +42 -4
- package/dist/optimization/session-cache.d.ts +13 -1
- package/dist/optimization/session-cache.js +27 -2
- package/dist/shared/llm/llm-router-service.js +59 -4
- package/dist/shared/llm/router/agent-router-config.d.ts +46 -2
- package/dist/shared/llm/router/agent-router-config.js +124 -2
- package/dist/shared/llm/router/config-store.d.ts +17 -1
- package/dist/shared/llm/router/config-store.js +103 -0
- package/dist/shared/llm/router/index.d.ts +2 -2
- package/dist/shared/llm/router/index.js +2 -0
- package/dist/shared/llm/router/types.d.ts +44 -0
- package/dist/shared/llm/router/types.js +1 -0
- package/package.json +9 -6
- package/dist/cli/chunks/adapter-CWIMFWAI.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-OTXT2DLN.js +0 -2
- package/dist/cli/chunks/base-O3SPSWBA.js +0 -2
- package/dist/cli/chunks/browser-workflow-MXS3ZKY2.js +0 -2
- package/dist/cli/chunks/chunk-G4GTE3RJ.js +0 -2
- package/dist/cli/chunks/chunk-G7FMYFTN.js +0 -2
- package/dist/cli/chunks/chunk-HVB2L52I.js +0 -2
- package/dist/cli/chunks/chunk-MVI2QMRW.js +0 -2
- package/dist/cli/chunks/chunk-OZR25R7W.js +0 -2
- package/dist/cli/chunks/chunk-PP2RYSHT.js +0 -3
- package/dist/cli/chunks/client-33PGO5FA.js +0 -2
- package/dist/cli/chunks/codex-installer-C2CUP4FW.js +0 -8
- package/dist/cli/chunks/core-handlers-CSNZIM3A.js +0 -2
- package/dist/cli/chunks/cross-domain-router-DRIBR5L3.js +0 -2
- package/dist/cli/chunks/dream-WUNO723O.js +0 -2
- package/dist/cli/chunks/heartbeat-scheduler-VAFQDJLL.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-TIRPA7XE.js +0 -2
- package/dist/cli/chunks/hnsw-index-SSQBRQCQ.js +0 -2
- package/dist/cli/chunks/hybrid-router-AKBWZOQ3.js +0 -2
- package/dist/cli/chunks/impact-analyzer-46FQIZ6Y.js +0 -2
- package/dist/cli/chunks/init-wizard-U3NHGYSS.js +0 -2
- package/dist/cli/chunks/kernel-ZDXHT6QF.js +0 -2
- package/dist/cli/chunks/knowledge-graph-6XTW6WO6.js +0 -2
- package/dist/cli/chunks/llm-router-service-3F4E64SY.js +0 -2
- package/dist/cli/chunks/load-test-SWZNGEIY.js +0 -2
- package/dist/cli/chunks/memory-backend-PR74ZPBA.js +0 -2
- package/dist/cli/chunks/pattern-null-store-EPE36BVT.js +0 -2
- package/dist/cli/chunks/protocol-executor-IELENNST.js +0 -2
- package/dist/cli/chunks/provider-manager-3R3KOBHG.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-S2R2PCBS.js +0 -2
- package/dist/cli/chunks/queen-coordinator-2E23NEV4.js +0 -2
- package/dist/cli/chunks/router-3FVLWO6S.js +0 -2
- package/dist/cli/chunks/routing-feedback-ZQLRNNR7.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-YFGLQNEB.js +0 -2
- package/dist/cli/chunks/safe-db-4SBLBTW7.js +0 -2
- package/dist/cli/chunks/schedule-5Y3BGVAA.js +0 -2
- package/dist/cli/chunks/scheduler-DOID3QF3.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-M4JEQO57.js +0 -2
- package/dist/cli/chunks/unified-memory-WNYWTGVX.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-YPAV7U4E.js +0 -2
- package/dist/cli/chunks/unified-persistence-TJ252S7L.js +0 -2
- package/dist/cli/chunks/visual-security-VKYXEGJB.js +0 -2
- package/dist/cli/chunks/witness-chain-WVXRXKQP.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-GOWSPR3G.js +0 -2
|
@@ -108,6 +108,9 @@ export const testGenerateConfig = {
|
|
|
108
108
|
const domainTests = data.tests;
|
|
109
109
|
const hasRealTests = Array.isArray(domainTests) && domainTests.length > 0
|
|
110
110
|
&& domainTests[0].testCode;
|
|
111
|
+
// #567: did the ADR-051 LLM branch actually run? Report it instead of
|
|
112
|
+
// asserting `aiGenerated: true` unconditionally.
|
|
113
|
+
const llmEnhanced = data.llmEnhanced === true;
|
|
111
114
|
const tests = hasRealTests
|
|
112
115
|
? domainTests.map((t, i) => ({
|
|
113
116
|
id: generateTestId(),
|
|
@@ -119,7 +122,7 @@ export const testGenerateConfig = {
|
|
|
119
122
|
: [`test assertion ${i}`],
|
|
120
123
|
expectedResult: null,
|
|
121
124
|
estimatedDuration: t.type === 'integration' ? 2000 : 1000,
|
|
122
|
-
aiGenerated:
|
|
125
|
+
aiGenerated: llmEnhanced,
|
|
123
126
|
testCode: t.testCode,
|
|
124
127
|
sourceFile: t.sourceFile,
|
|
125
128
|
testFile: t.testFile || t.file,
|
|
@@ -133,7 +136,9 @@ export const testGenerateConfig = {
|
|
|
133
136
|
aiInsights,
|
|
134
137
|
coverage: {
|
|
135
138
|
predicted: data.coverageEstimate || params?.coverageGoal || 80,
|
|
136
|
-
|
|
139
|
+
// #567: a template scaffold's coverage prediction is a guess, not a
|
|
140
|
+
// 0.9-confidence estimate. Don't dress it up as one.
|
|
141
|
+
confidence: llmEnhanced ? 0.9 : 0.3,
|
|
137
142
|
achievable: true,
|
|
138
143
|
},
|
|
139
144
|
properties: tests.filter(t => t.type === 'property').map(t => ({
|
|
@@ -151,6 +156,10 @@ export const testGenerateConfig = {
|
|
|
151
156
|
patternsUsed: data.patternsUsed || ['assertion-patterns', 'mock-generation', 'edge-case-detection'],
|
|
152
157
|
duration,
|
|
153
158
|
savedFiles,
|
|
159
|
+
// #567: propagate the LLM-enhancement signal to the MCP caller.
|
|
160
|
+
llmEnhanced,
|
|
161
|
+
...(data.generationMode ? { generationMode: data.generationMode } : {}),
|
|
162
|
+
...(data.note ? { note: data.note } : {}),
|
|
154
163
|
};
|
|
155
164
|
},
|
|
156
165
|
};
|
|
@@ -253,12 +262,40 @@ export const coverageAnalyzeConfig = {
|
|
|
253
262
|
// The domain returns CoverageReport { summary: { line, branch, function, statement, files }, ... }
|
|
254
263
|
// Map from both nested (domain) and flat (legacy) field shapes.
|
|
255
264
|
const summary = data.summary;
|
|
256
|
-
const lineCoverage = summary?.line ?? data.lineCoverage ?? 0;
|
|
257
|
-
const branchCoverage = summary?.branch ?? data.branchCoverage ?? 0;
|
|
258
|
-
const functionCoverage = summary?.function ?? data.functionCoverage ?? 0;
|
|
259
|
-
const statementCoverage = summary?.statement ?? data.statementCoverage ?? lineCoverage;
|
|
260
265
|
const totalFiles = summary?.files ?? data.totalFiles ?? 0;
|
|
261
266
|
const gaps = data.gaps || [];
|
|
267
|
+
// #569/ADR-126: an ABSENT provenance flag means "unknown", never "collected".
|
|
268
|
+
//
|
|
269
|
+
// Defaulting these to `true` (`!== false`) meant any producer that supplies
|
|
270
|
+
// no provenance at all — notably the coverage-analysis domain plugin, whose
|
|
271
|
+
// handler returns a nested-`summary` CoverageReport — surfaced the exact
|
|
272
|
+
// impossible pair from the issue: 100% branch coverage alongside 0% function
|
|
273
|
+
// coverage, labelled `measured: true` with `confidence: 0.7` on its gaps.
|
|
274
|
+
// Requiring an explicit `true` makes an unprovenanced result honest (`null`)
|
|
275
|
+
// instead of confidently wrong.
|
|
276
|
+
const branchDataCollected = data.branchDataCollected === true;
|
|
277
|
+
const functionDataCollected = data.functionDataCollected === true;
|
|
278
|
+
const branchCoverage = branchDataCollected
|
|
279
|
+
? (summary?.branch ?? data.branchCoverage ?? null)
|
|
280
|
+
: null;
|
|
281
|
+
const functionCoverage = functionDataCollected
|
|
282
|
+
? (summary?.function ?? data.functionCoverage ?? null)
|
|
283
|
+
: null;
|
|
284
|
+
// #569: is this a measurement or a static estimate? Everything downstream —
|
|
285
|
+
// gap confidence, AI insights, risk assessment — must be qualified by it.
|
|
286
|
+
const estimated = data.estimated === true;
|
|
287
|
+
// #569/ADR-126: `measured` is NOT the complement of `estimated` — there is a
|
|
288
|
+
// third state where nothing was collected at all. Deriving it as `!estimated`
|
|
289
|
+
// reported an empty project (no sources, no coverage report, nothing run) as
|
|
290
|
+
// `lineCoverage: 0, measured: true` — "we measured 0%" when the truth is "we
|
|
291
|
+
// measured nothing". Trust only an explicit claim from the producer.
|
|
292
|
+
const measured = data.measured === true;
|
|
293
|
+
// Likewise, a `null` line/statement figure must survive as `null`. `?? 0`
|
|
294
|
+
// turns "no data" into a plottable 0%.
|
|
295
|
+
const rawLine = summary?.line ?? data.lineCoverage;
|
|
296
|
+
const lineCoverage = rawLine ?? null;
|
|
297
|
+
const rawStatement = summary?.statement ?? data.statementCoverage;
|
|
298
|
+
const statementCoverage = rawStatement ?? lineCoverage;
|
|
262
299
|
const learning = generateV2LearningFeedback('coverage-analyzer');
|
|
263
300
|
// Map gap analysis from real data — never fabricate file paths
|
|
264
301
|
const detailedGaps = gaps.map((gap, i) => {
|
|
@@ -278,7 +315,12 @@ export const coverageAnalyzeConfig = {
|
|
|
278
315
|
suggestion: g.suggestedTest || 'Add test coverage',
|
|
279
316
|
suggestedTest: g.suggestedTest || 'Add test coverage',
|
|
280
317
|
riskScore: g.riskScore || 0.5,
|
|
281
|
-
|
|
318
|
+
// #569: the 0.7 default confidence is only defensible for a gap derived
|
|
319
|
+
// from a real measurement. An estimated gap carries its own low
|
|
320
|
+
// confidence from the handler; a gap with no provenance at all is not
|
|
321
|
+
// known to be measured either, so it gets the cautious value too.
|
|
322
|
+
confidence: g.confidence ?? (measured ? 0.7 : 0.2),
|
|
323
|
+
estimated: g.estimated === true || estimated,
|
|
282
324
|
};
|
|
283
325
|
}).filter((g) => g !== null);
|
|
284
326
|
// Use real file data from the analyzer if available, never fabricate file paths
|
|
@@ -287,8 +329,9 @@ export const coverageAnalyzeConfig = {
|
|
|
287
329
|
? coverageByFileData.map(f => ({
|
|
288
330
|
file: f.file,
|
|
289
331
|
lineCoverage: f.lineCoverage || 0,
|
|
290
|
-
|
|
291
|
-
|
|
332
|
+
// #569: preserve null (metric not collected) instead of collapsing to 0.
|
|
333
|
+
branchCoverage: f.branchCoverage ?? null,
|
|
334
|
+
functionCoverage: f.functionCoverage ?? null,
|
|
292
335
|
}))
|
|
293
336
|
: [];
|
|
294
337
|
return {
|
|
@@ -305,11 +348,25 @@ export const coverageAnalyzeConfig = {
|
|
|
305
348
|
weeklyChange: 0,
|
|
306
349
|
},
|
|
307
350
|
aiInsights: totalFiles > 0 ? {
|
|
308
|
-
recommendations:
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
351
|
+
recommendations: estimated
|
|
352
|
+
// #569: the reported insights ("Coverage is 15.9% below threshold",
|
|
353
|
+
// "Function coverage is below 70%") were all derived from estimated
|
|
354
|
+
// numbers and presented as findings. Lead with the caveat.
|
|
355
|
+
? [
|
|
356
|
+
'ESTIMATED RESULT — no instrumentation ran. The figures below are a ' +
|
|
357
|
+
'static guess from source shape, not measured coverage. Do not act on ' +
|
|
358
|
+
'individual gaps without running real instrumentation first.',
|
|
359
|
+
...(data.recommendations || []),
|
|
360
|
+
]
|
|
361
|
+
: (data.recommendations || [
|
|
362
|
+
'Run tests with coverage enabled to get accurate metrics',
|
|
363
|
+
]),
|
|
364
|
+
// #569: risk can only be graded off a real number. `null < 70` is
|
|
365
|
+
// `false` in JS, which would have silently graded "no data" as 'low'.
|
|
366
|
+
riskAssessment: (estimated || !measured || lineCoverage === null)
|
|
367
|
+
? 'unknown'
|
|
368
|
+
: (lineCoverage < 70 ? 'high' : lineCoverage < 85 ? 'medium' : 'low'),
|
|
369
|
+
confidence: estimated ? 0.2 : (measured ? 0.88 : 0),
|
|
313
370
|
} : {
|
|
314
371
|
recommendations: [
|
|
315
372
|
'No coverage data found. Run tests with coverage first (e.g., npm test -- --coverage, or pytest --cov)',
|
|
@@ -329,6 +386,14 @@ export const coverageAnalyzeConfig = {
|
|
|
329
386
|
gaps: detailedGaps,
|
|
330
387
|
duration,
|
|
331
388
|
savedFiles,
|
|
389
|
+
// #569: provenance travels with the numbers so a caller can never mistake
|
|
390
|
+
// a static estimate for a measurement.
|
|
391
|
+
estimated,
|
|
392
|
+
measured,
|
|
393
|
+
coverageMethod: data.coverageMethod ?? 'unknown',
|
|
394
|
+
branchDataCollected,
|
|
395
|
+
functionDataCollected,
|
|
396
|
+
...(data.warning ? { warning: data.warning } : {}),
|
|
332
397
|
};
|
|
333
398
|
},
|
|
334
399
|
};
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -446,6 +446,15 @@ export interface TestGenerateResult {
|
|
|
446
446
|
suggestions?: string[];
|
|
447
447
|
savedFiles?: string[];
|
|
448
448
|
patternsUsed?: string[];
|
|
449
|
+
/**
|
|
450
|
+
* #567: true when the ADR-051 LLM branch actually ran. When false the tests
|
|
451
|
+
* are deterministic template scaffolding — see `generationMode`/`note`.
|
|
452
|
+
*/
|
|
453
|
+
llmEnhanced?: boolean;
|
|
454
|
+
/** #567: set to 'deterministic-template' when no LLM enhancement was applied. */
|
|
455
|
+
generationMode?: string;
|
|
456
|
+
/** #567: human-readable reason the LLM branch did not run. */
|
|
457
|
+
note?: string;
|
|
449
458
|
tests?: unknown[];
|
|
450
459
|
antiPatterns?: unknown[];
|
|
451
460
|
aiInsights?: Record<string, unknown>;
|
|
@@ -462,19 +471,46 @@ export interface CoverageAnalyzeResult {
|
|
|
462
471
|
taskId: string;
|
|
463
472
|
status: string;
|
|
464
473
|
duration: number;
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
474
|
+
/**
|
|
475
|
+
* #569: `null` when no coverage figure was produced at all (no report, no
|
|
476
|
+
* instrumentation run, nothing to estimate from). `0` means a measured zero;
|
|
477
|
+
* `null` means "we don't know" — the two must not be conflated.
|
|
478
|
+
*/
|
|
479
|
+
lineCoverage: number | null;
|
|
480
|
+
/**
|
|
481
|
+
* #569: `null` when branch data was not collected. Never report a branch
|
|
482
|
+
* percentage — least of all 100% — that no instrumentation produced.
|
|
483
|
+
*/
|
|
484
|
+
branchCoverage: number | null;
|
|
485
|
+
/** #569: `null` when function-level data was not collected. */
|
|
486
|
+
functionCoverage: number | null;
|
|
468
487
|
gaps?: CoverageGap[];
|
|
469
488
|
riskScore?: number;
|
|
470
489
|
savedFiles?: string[];
|
|
471
|
-
|
|
490
|
+
/** #569: `null` when no figure was produced — see `lineCoverage`. */
|
|
491
|
+
statementCoverage?: number | null;
|
|
472
492
|
totalFiles?: number;
|
|
473
493
|
coverageByFile?: unknown[];
|
|
474
494
|
gapAnalysis?: Record<string, unknown>;
|
|
475
495
|
trends?: Record<string, unknown>;
|
|
476
496
|
aiInsights?: Record<string, unknown>;
|
|
477
497
|
learning?: Record<string, unknown>;
|
|
498
|
+
/**
|
|
499
|
+
* #569 provenance. `true` means the figures are a STATIC ESTIMATE derived
|
|
500
|
+
* from source shape, not measured coverage. Callers must not present an
|
|
501
|
+
* estimated result as a measurement.
|
|
502
|
+
*/
|
|
503
|
+
estimated?: boolean;
|
|
504
|
+
/** Inverse of `estimated`: real instrumentation produced these numbers. */
|
|
505
|
+
measured?: boolean;
|
|
506
|
+
/** How the numbers were obtained: instrumented-report | cargo-llvm-cov | static-estimation | none. */
|
|
507
|
+
coverageMethod?: string;
|
|
508
|
+
/** Whether branch data was actually collected. */
|
|
509
|
+
branchDataCollected?: boolean;
|
|
510
|
+
/** Whether function-level data was actually collected. */
|
|
511
|
+
functionDataCollected?: boolean;
|
|
512
|
+
/** Caveats the caller should surface (e.g. "no instrumentation ran"). */
|
|
513
|
+
warning?: string;
|
|
478
514
|
}
|
|
479
515
|
/**
|
|
480
516
|
* Coverage gap
|
|
@@ -492,6 +528,8 @@ export interface CoverageGap {
|
|
|
492
528
|
priority?: string;
|
|
493
529
|
suggestedTest?: string;
|
|
494
530
|
riskScore?: number;
|
|
531
|
+
/** #569: true when this gap came from a static estimate, not a measurement. */
|
|
532
|
+
estimated?: boolean;
|
|
495
533
|
}
|
|
496
534
|
/**
|
|
497
535
|
* Memory store result
|
|
@@ -47,8 +47,20 @@ export declare class SessionOperationCache {
|
|
|
47
47
|
private misses;
|
|
48
48
|
constructor(config?: Partial<SessionCacheConfig>);
|
|
49
49
|
/**
|
|
50
|
-
* Compute a deterministic fingerprint from domain + action + input.
|
|
50
|
+
* Compute a deterministic fingerprint from build + domain + action + input.
|
|
51
51
|
* Uses SHA-256 of the canonicalized JSON (recursively sorted keys), truncated to 16 hex chars.
|
|
52
|
+
*
|
|
53
|
+
* The build identity is part of the key on purpose. Entries are persisted to
|
|
54
|
+
* `kv_store` and survive process restarts *and package upgrades*, so a
|
|
55
|
+
* fingerprint over inputs alone means an upgraded install keeps replaying the
|
|
56
|
+
* previous version's answers until the TTL lapses — the fix looks like it did
|
|
57
|
+
* not work. That is exactly what happened while verifying issue #569: a
|
|
58
|
+
* project analyzed before the fix kept returning the old fabricated coverage
|
|
59
|
+
* numbers (`lineCoverage: 0, measured: true`) from cache, while an untouched
|
|
60
|
+
* project returned the corrected result.
|
|
61
|
+
*
|
|
62
|
+
* Including the version means an upgrade misses cleanly rather than serving
|
|
63
|
+
* stale answers; entries from the old build simply age out.
|
|
52
64
|
*/
|
|
53
65
|
computeFingerprint(domain: string, action: string, input: Record<string, unknown>): string;
|
|
54
66
|
/**
|
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
* - TTL-based expiry, LRU-ish eviction at capacity
|
|
14
14
|
*/
|
|
15
15
|
import { createHash } from 'crypto';
|
|
16
|
+
/**
|
|
17
|
+
* Build identity mixed into every cache fingerprint so persisted entries never
|
|
18
|
+
* outlive the code that produced them. `__CLI_VERSION__` is substituted at bundle
|
|
19
|
+
* time; in source/test runs it is undefined and we fall back to a dev marker.
|
|
20
|
+
*
|
|
21
|
+
* `AQE_SESSION_CACHE_SALT` lets an operator force a cold cache without deleting
|
|
22
|
+
* anything (e.g. after a local rebuild that keeps the same version string).
|
|
23
|
+
*/
|
|
24
|
+
function getBuildIdentity() {
|
|
25
|
+
const version = typeof __CLI_VERSION__ !== 'undefined' ? __CLI_VERSION__ : 'dev';
|
|
26
|
+
const salt = (process.env.AQE_SESSION_CACHE_SALT ?? '').trim();
|
|
27
|
+
return salt ? `${version}+${salt}` : version;
|
|
28
|
+
}
|
|
16
29
|
export const DEFAULT_SESSION_CACHE_CONFIG = {
|
|
17
30
|
enabled: true,
|
|
18
31
|
maxEntries: 500,
|
|
@@ -51,11 +64,23 @@ export class SessionOperationCache {
|
|
|
51
64
|
this.config = { ...DEFAULT_SESSION_CACHE_CONFIG, ...config };
|
|
52
65
|
}
|
|
53
66
|
/**
|
|
54
|
-
* Compute a deterministic fingerprint from domain + action + input.
|
|
67
|
+
* Compute a deterministic fingerprint from build + domain + action + input.
|
|
55
68
|
* Uses SHA-256 of the canonicalized JSON (recursively sorted keys), truncated to 16 hex chars.
|
|
69
|
+
*
|
|
70
|
+
* The build identity is part of the key on purpose. Entries are persisted to
|
|
71
|
+
* `kv_store` and survive process restarts *and package upgrades*, so a
|
|
72
|
+
* fingerprint over inputs alone means an upgraded install keeps replaying the
|
|
73
|
+
* previous version's answers until the TTL lapses — the fix looks like it did
|
|
74
|
+
* not work. That is exactly what happened while verifying issue #569: a
|
|
75
|
+
* project analyzed before the fix kept returning the old fabricated coverage
|
|
76
|
+
* numbers (`lineCoverage: 0, measured: true`) from cache, while an untouched
|
|
77
|
+
* project returned the corrected result.
|
|
78
|
+
*
|
|
79
|
+
* Including the version means an upgrade misses cleanly rather than serving
|
|
80
|
+
* stale answers; entries from the old build simply age out.
|
|
56
81
|
*/
|
|
57
82
|
computeFingerprint(domain, action, input) {
|
|
58
|
-
const canonical = canonicalStringify({ action, domain, input });
|
|
83
|
+
const canonical = canonicalStringify({ action, build: getBuildIdentity(), domain, input });
|
|
59
84
|
return createHash('sha256').update(canonical).digest('hex').slice(0, 16);
|
|
60
85
|
}
|
|
61
86
|
/**
|
|
@@ -22,6 +22,47 @@
|
|
|
22
22
|
import { ProviderManager } from './provider-manager.js';
|
|
23
23
|
import { HybridRouter } from './router/hybrid-router.js';
|
|
24
24
|
import { loadRouterConfig, shouldEnableRouter, detectAvailableProvidersFromEnv, } from './router/config-store.js';
|
|
25
|
+
import { setAgentProviderOverrides, createOverrideRoutingRules, } from './router/agent-router-config.js';
|
|
26
|
+
import { DEFAULT_QE_ROUTING_RULES } from './router/routing-rules.js';
|
|
27
|
+
import { createLogger } from '../../logging/logger-factory.js';
|
|
28
|
+
const routerServiceLogger = createLogger('llm/router-service');
|
|
29
|
+
/**
|
|
30
|
+
* Issue #568: make `.agentic-qe/llm-config.json`'s `agentOverrides` map actually
|
|
31
|
+
* take effect.
|
|
32
|
+
*
|
|
33
|
+
* Two steps, and both are needed:
|
|
34
|
+
* 1. install the map so `getPreferredModelForAgent()` consults it, and
|
|
35
|
+
* 2. materialize a routing rule per overridden agent and put it *ahead* of the
|
|
36
|
+
* rules the router would otherwise evaluate.
|
|
37
|
+
*
|
|
38
|
+
* Step 2 is the part that was missing before: `HybridRouter` only ever evaluates
|
|
39
|
+
* `config.rules` (falling back to `DEFAULT_QE_ROUTING_RULES`), and the generated
|
|
40
|
+
* per-agent ruleset was never installed into either — which is why the whole
|
|
41
|
+
* `agent-router-config` mechanism was unreachable from outside a single call
|
|
42
|
+
* stack.
|
|
43
|
+
*
|
|
44
|
+
* No overrides on disk => returns the config untouched.
|
|
45
|
+
*/
|
|
46
|
+
function applyAgentOverrides(config) {
|
|
47
|
+
// Pass each provider's own default model so a `{ "provider": "ollama" }`
|
|
48
|
+
// override resolves to a model ollama can serve, not the Claude model id the
|
|
49
|
+
// agent's category default happened to carry.
|
|
50
|
+
const providerDefaultModels = {};
|
|
51
|
+
for (const [provider, cfg] of Object.entries(config.providers ?? {})) {
|
|
52
|
+
if (cfg?.defaultModel) {
|
|
53
|
+
providerDefaultModels[provider] = cfg.defaultModel;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
setAgentProviderOverrides(config.agentOverrides, providerDefaultModels);
|
|
57
|
+
const overrideRules = createOverrideRoutingRules();
|
|
58
|
+
if (overrideRules.length === 0) {
|
|
59
|
+
return config;
|
|
60
|
+
}
|
|
61
|
+
// Mirror HybridRouter's own fallback so materializing overrides never has the
|
|
62
|
+
// side effect of dropping the default QE rules.
|
|
63
|
+
const baseRules = config.rules.length > 0 ? config.rules : DEFAULT_QE_ROUTING_RULES;
|
|
64
|
+
return { ...config, rules: [...overrideRules, ...baseRules] };
|
|
65
|
+
}
|
|
25
66
|
/**
|
|
26
67
|
* Order in which we pick fallbacks when the user hasn't specified any.
|
|
27
68
|
* Local-first (free), then cheapest cloud, then richer providers. This
|
|
@@ -46,11 +87,11 @@ const FALLBACK_PRIORITY = [
|
|
|
46
87
|
export async function createLLMRouterService(options = {}) {
|
|
47
88
|
// Honor the test-injected ProviderManager path first.
|
|
48
89
|
if (options.providerManager) {
|
|
49
|
-
const config = loadRouterConfig({
|
|
90
|
+
const config = applyAgentOverrides(loadRouterConfig({
|
|
50
91
|
projectRoot: options.projectRoot,
|
|
51
92
|
override: options.override,
|
|
52
93
|
env: options.env,
|
|
53
|
-
});
|
|
94
|
+
}));
|
|
54
95
|
const router = new HybridRouter(options.providerManager, config);
|
|
55
96
|
await router.initialize();
|
|
56
97
|
return {
|
|
@@ -63,15 +104,29 @@ export async function createLLMRouterService(options = {}) {
|
|
|
63
104
|
if (!shouldEnableRouter({ projectRoot: options.projectRoot, env: options.env })) {
|
|
64
105
|
return null;
|
|
65
106
|
}
|
|
66
|
-
const config = loadRouterConfig({
|
|
107
|
+
const config = applyAgentOverrides(loadRouterConfig({
|
|
67
108
|
projectRoot: options.projectRoot,
|
|
68
109
|
override: options.override,
|
|
69
110
|
env: options.env,
|
|
70
|
-
});
|
|
111
|
+
}));
|
|
71
112
|
const enabled = pickEnabledProviders(config, options.env ?? process.env);
|
|
72
113
|
if (enabled.length === 0) {
|
|
73
114
|
return null;
|
|
74
115
|
}
|
|
116
|
+
// Issue #568: an override naming a provider that isn't enabled would silently
|
|
117
|
+
// fall through to the default chain — the exact "configured it and nothing
|
|
118
|
+
// happened" failure this feature exists to avoid. Say so out loud. We do NOT
|
|
119
|
+
// auto-enable it: that would opt the user into a provider (and possibly paid
|
|
120
|
+
// billing) they never turned on.
|
|
121
|
+
const enabledSet = new Set(enabled);
|
|
122
|
+
for (const [agentType, override] of Object.entries(config.agentOverrides ?? {})) {
|
|
123
|
+
if (override.provider && !enabledSet.has(override.provider)) {
|
|
124
|
+
routerServiceLogger.warn(`[llm-config] agentOverrides["${agentType}"] routes to provider ` +
|
|
125
|
+
`"${override.provider}", which is not enabled (no API key detected and not ` +
|
|
126
|
+
`enabled in .agentic-qe/llm-config.json). This override will not take effect ` +
|
|
127
|
+
`until that provider is available.`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
75
130
|
const { primary, fallbacks } = pickPrimaryAndFallbacks(config, enabled);
|
|
76
131
|
const providerManagerConfig = {
|
|
77
132
|
primary: primary,
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Override mechanism for specific tasks
|
|
9
9
|
* - Agent category detection and preferred model resolution
|
|
10
10
|
*/
|
|
11
|
-
import { ExtendedProviderType, RoutingRule, TaskComplexity } from './types';
|
|
11
|
+
import { ExtendedProviderType, RoutingRule, TaskComplexity, AgentProviderOverride } from './types';
|
|
12
12
|
/**
|
|
13
13
|
* Agent categories for routing decisions
|
|
14
14
|
*/
|
|
@@ -120,7 +120,34 @@ export declare const DEFAULT_CATEGORY_CAPABILITIES: Record<AgentCategory, AgentC
|
|
|
120
120
|
*/
|
|
121
121
|
export declare function getAgentRoutingCategory(agentType: string): AgentCategory;
|
|
122
122
|
/**
|
|
123
|
-
*
|
|
123
|
+
* Install the on-disk per-agent overrides (issue #568). Called by the router
|
|
124
|
+
* service after `loadRouterConfig()` has validated them.
|
|
125
|
+
*
|
|
126
|
+
* Replaces the whole map rather than merging, so reloading a config that
|
|
127
|
+
* removed an entry actually removes it.
|
|
128
|
+
*
|
|
129
|
+
* @param overrides validated `agentOverrides` map
|
|
130
|
+
* @param defaultModels per-provider default model ids, so a provider-only
|
|
131
|
+
* override resolves to a model that provider can actually serve
|
|
132
|
+
*/
|
|
133
|
+
export declare function setAgentProviderOverrides(overrides: Record<string, AgentProviderOverride> | undefined, defaultModels?: Partial<Record<ExtendedProviderType, string>>): void;
|
|
134
|
+
/** Current on-disk per-agent overrides. Primarily for diagnostics and tests. */
|
|
135
|
+
export declare function getAgentProviderOverrides(): Readonly<Record<string, AgentProviderOverride>>;
|
|
136
|
+
/** Clear installed overrides. For tests. */
|
|
137
|
+
export declare function resetAgentProviderOverrides(): void;
|
|
138
|
+
/**
|
|
139
|
+
* Get the preferred model for an agent type.
|
|
140
|
+
*
|
|
141
|
+
* Resolution order (issue #568):
|
|
142
|
+
* 1. `agentOverrides[agentType]` from `.agentic-qe/llm-config.json` — the
|
|
143
|
+
* user's explicit, hand-written intent, so it wins.
|
|
144
|
+
* 2. the agent's category default (`AGENT_CATEGORY_MAP` ->
|
|
145
|
+
* `DEFAULT_CATEGORY_MODELS`).
|
|
146
|
+
*
|
|
147
|
+
* An override is a *partial*: fields it does not set keep their category
|
|
148
|
+
* default, so `{ "provider": "ollama" }` re-provisions the provider without
|
|
149
|
+
* forcing the user to also restate temperature, token budget, and priority.
|
|
150
|
+
*
|
|
124
151
|
* @param agentType - The agent type identifier
|
|
125
152
|
* @returns The model preference configuration
|
|
126
153
|
*/
|
|
@@ -161,6 +188,23 @@ export declare function isLatencySensitive(agentType: string): boolean;
|
|
|
161
188
|
* @returns A routing rule for this agent type
|
|
162
189
|
*/
|
|
163
190
|
export declare function createAgentRoutingRule(agentType: string): RoutingRule;
|
|
191
|
+
/**
|
|
192
|
+
* Build routing rules for exactly the agent types the user overrode on disk
|
|
193
|
+
* (issue #568).
|
|
194
|
+
*
|
|
195
|
+
* Why a separate builder rather than `createAgentRoutingRule`: that one also
|
|
196
|
+
* constrains on `requiresReasoning`, which is right for the generated
|
|
197
|
+
* whole-roster ruleset but wrong here — a user who wrote
|
|
198
|
+
* `"qe-mutation-tester": { "provider": "ollama" }` means *always*, not "only when
|
|
199
|
+
* the request happens to be flagged as needing reasoning". These rules match on
|
|
200
|
+
* agent type alone.
|
|
201
|
+
*
|
|
202
|
+
* Returns `[]` when nothing is overridden, so a project without the key gets the
|
|
203
|
+
* exact rule set it got before.
|
|
204
|
+
*
|
|
205
|
+
* @returns Routing rules, highest priority first
|
|
206
|
+
*/
|
|
207
|
+
export declare function createOverrideRoutingRules(): RoutingRule[];
|
|
164
208
|
/**
|
|
165
209
|
* Create routing rules for all agents in a category
|
|
166
210
|
* @param category - The agent category
|
|
@@ -324,14 +324,97 @@ export function getAgentRoutingCategory(agentType) {
|
|
|
324
324
|
}
|
|
325
325
|
return 'general';
|
|
326
326
|
}
|
|
327
|
+
// ============================================================================
|
|
328
|
+
// On-disk per-agent overrides (issue #568)
|
|
329
|
+
// ============================================================================
|
|
330
|
+
/**
|
|
331
|
+
* Per-agent-type overrides sourced from `.agentic-qe/llm-config.json`'s
|
|
332
|
+
* `agentOverrides` key.
|
|
333
|
+
*
|
|
334
|
+
* Module-level state, deliberately: `getPreferredModelForAgent` is a synchronous
|
|
335
|
+
* pure-lookup function called from many places (rule construction, capability
|
|
336
|
+
* resolution, the router's own dispatch), and threading a config object through
|
|
337
|
+
* all of them would be a far larger change than this feature warrants. The
|
|
338
|
+
* router installs the loaded map once at construction via
|
|
339
|
+
* `setAgentProviderOverrides`.
|
|
340
|
+
*
|
|
341
|
+
* Empty by default, so behavior is unchanged for anyone who never writes the
|
|
342
|
+
* key — the category defaults below remain authoritative.
|
|
343
|
+
*/
|
|
344
|
+
let agentProviderOverrides = {};
|
|
345
|
+
/**
|
|
346
|
+
* Per-provider default model, from the router config's `providers` map.
|
|
347
|
+
*
|
|
348
|
+
* Needed because the category defaults in `DEFAULT_CATEGORY_MODELS` pair a
|
|
349
|
+
* provider with a provider-specific model id. If a user writes
|
|
350
|
+
* `{ "provider": "ollama" }` and we inherited the category *model* too, the
|
|
351
|
+
* agent would be routed to ollama asking for `claude-sonnet-4-6` — a model that
|
|
352
|
+
* provider cannot serve. Changing provider without naming a model must fall
|
|
353
|
+
* back to that provider's own default, not the previous provider's model.
|
|
354
|
+
*/
|
|
355
|
+
let providerDefaultModels = {};
|
|
356
|
+
/**
|
|
357
|
+
* Install the on-disk per-agent overrides (issue #568). Called by the router
|
|
358
|
+
* service after `loadRouterConfig()` has validated them.
|
|
359
|
+
*
|
|
360
|
+
* Replaces the whole map rather than merging, so reloading a config that
|
|
361
|
+
* removed an entry actually removes it.
|
|
362
|
+
*
|
|
363
|
+
* @param overrides validated `agentOverrides` map
|
|
364
|
+
* @param defaultModels per-provider default model ids, so a provider-only
|
|
365
|
+
* override resolves to a model that provider can actually serve
|
|
366
|
+
*/
|
|
367
|
+
export function setAgentProviderOverrides(overrides, defaultModels) {
|
|
368
|
+
agentProviderOverrides = { ...(overrides ?? {}) };
|
|
369
|
+
providerDefaultModels = { ...(defaultModels ?? {}) };
|
|
370
|
+
}
|
|
371
|
+
/** Current on-disk per-agent overrides. Primarily for diagnostics and tests. */
|
|
372
|
+
export function getAgentProviderOverrides() {
|
|
373
|
+
return agentProviderOverrides;
|
|
374
|
+
}
|
|
375
|
+
/** Clear installed overrides. For tests. */
|
|
376
|
+
export function resetAgentProviderOverrides() {
|
|
377
|
+
agentProviderOverrides = {};
|
|
378
|
+
providerDefaultModels = {};
|
|
379
|
+
}
|
|
327
380
|
/**
|
|
328
|
-
* Get the preferred model for an agent type
|
|
381
|
+
* Get the preferred model for an agent type.
|
|
382
|
+
*
|
|
383
|
+
* Resolution order (issue #568):
|
|
384
|
+
* 1. `agentOverrides[agentType]` from `.agentic-qe/llm-config.json` — the
|
|
385
|
+
* user's explicit, hand-written intent, so it wins.
|
|
386
|
+
* 2. the agent's category default (`AGENT_CATEGORY_MAP` ->
|
|
387
|
+
* `DEFAULT_CATEGORY_MODELS`).
|
|
388
|
+
*
|
|
389
|
+
* An override is a *partial*: fields it does not set keep their category
|
|
390
|
+
* default, so `{ "provider": "ollama" }` re-provisions the provider without
|
|
391
|
+
* forcing the user to also restate temperature, token budget, and priority.
|
|
392
|
+
*
|
|
329
393
|
* @param agentType - The agent type identifier
|
|
330
394
|
* @returns The model preference configuration
|
|
331
395
|
*/
|
|
332
396
|
export function getPreferredModelForAgent(agentType) {
|
|
333
397
|
const category = getAgentRoutingCategory(agentType);
|
|
334
|
-
|
|
398
|
+
const base = DEFAULT_CATEGORY_MODELS[category];
|
|
399
|
+
const override = agentProviderOverrides[agentType];
|
|
400
|
+
if (!override)
|
|
401
|
+
return base;
|
|
402
|
+
// Changing provider without naming a model must NOT inherit the previous
|
|
403
|
+
// provider's model id (see `providerDefaultModels`). Prefer that provider's
|
|
404
|
+
// own default; only keep the category model when the provider is unchanged.
|
|
405
|
+
const switchingProvider = override.provider !== undefined && override.provider !== base.provider;
|
|
406
|
+
const resolvedModel = override.model ??
|
|
407
|
+
(switchingProvider ? providerDefaultModels[override.provider] : undefined);
|
|
408
|
+
return {
|
|
409
|
+
...base,
|
|
410
|
+
...(override.provider !== undefined ? { provider: override.provider } : {}),
|
|
411
|
+
...(resolvedModel !== undefined ? { model: resolvedModel } : {}),
|
|
412
|
+
...(override.temperature !== undefined ? { temperature: override.temperature } : {}),
|
|
413
|
+
...(override.maxTokens !== undefined ? { maxTokens: override.maxTokens } : {}),
|
|
414
|
+
// An explicit on-disk entry outranks the built-in category rule by default,
|
|
415
|
+
// so it isn't quietly out-prioritized by DEFAULT_ROUTING_OVERRIDES.
|
|
416
|
+
priority: override.priority ?? base.priority + 100,
|
|
417
|
+
};
|
|
335
418
|
}
|
|
336
419
|
/**
|
|
337
420
|
* Get capability requirements for an agent type
|
|
@@ -410,6 +493,45 @@ export function createAgentRoutingRule(agentType) {
|
|
|
410
493
|
priority: preference.priority,
|
|
411
494
|
};
|
|
412
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* Build routing rules for exactly the agent types the user overrode on disk
|
|
498
|
+
* (issue #568).
|
|
499
|
+
*
|
|
500
|
+
* Why a separate builder rather than `createAgentRoutingRule`: that one also
|
|
501
|
+
* constrains on `requiresReasoning`, which is right for the generated
|
|
502
|
+
* whole-roster ruleset but wrong here — a user who wrote
|
|
503
|
+
* `"qe-mutation-tester": { "provider": "ollama" }` means *always*, not "only when
|
|
504
|
+
* the request happens to be flagged as needing reasoning". These rules match on
|
|
505
|
+
* agent type alone.
|
|
506
|
+
*
|
|
507
|
+
* Returns `[]` when nothing is overridden, so a project without the key gets the
|
|
508
|
+
* exact rule set it got before.
|
|
509
|
+
*
|
|
510
|
+
* @returns Routing rules, highest priority first
|
|
511
|
+
*/
|
|
512
|
+
export function createOverrideRoutingRules() {
|
|
513
|
+
return Object.keys(agentProviderOverrides)
|
|
514
|
+
.map((agentType) => {
|
|
515
|
+
const preference = getPreferredModelForAgent(agentType);
|
|
516
|
+
return {
|
|
517
|
+
id: `agent-override-${agentType}`,
|
|
518
|
+
name: `User override: ${agentType} -> ${preference.provider}/${preference.model}`,
|
|
519
|
+
description: `Per-agent routing override from .agentic-qe/llm-config.json ` +
|
|
520
|
+
`(agentOverrides["${agentType}"])`,
|
|
521
|
+
condition: { agentType: [agentType] },
|
|
522
|
+
action: {
|
|
523
|
+
provider: preference.provider,
|
|
524
|
+
model: preference.model,
|
|
525
|
+
temperature: preference.temperature,
|
|
526
|
+
maxTokens: preference.maxTokens,
|
|
527
|
+
priority: preference.priority,
|
|
528
|
+
},
|
|
529
|
+
enabled: true,
|
|
530
|
+
priority: preference.priority,
|
|
531
|
+
};
|
|
532
|
+
})
|
|
533
|
+
.sort((a, b) => b.priority - a.priority);
|
|
534
|
+
}
|
|
413
535
|
/**
|
|
414
536
|
* Create routing rules for all agents in a category
|
|
415
537
|
* @param category - The agent category
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* state — we don't disable it implicitly, because users may set keys
|
|
18
18
|
* later via `aqe llm config --set`.
|
|
19
19
|
*/
|
|
20
|
-
import type { RouterConfig, ExtendedProviderType } from './types.js';
|
|
20
|
+
import type { RouterConfig, ExtendedProviderType, AgentProviderOverride } from './types.js';
|
|
21
21
|
/** Filename under .agentic-qe/ */
|
|
22
22
|
export declare const ROUTER_CONFIG_FILENAME = "llm-config.json";
|
|
23
23
|
/**
|
|
@@ -52,6 +52,22 @@ export declare function saveRouterConfigFile(config: Partial<RouterConfig>, proj
|
|
|
52
52
|
* top-level scalars use last-wins.
|
|
53
53
|
*/
|
|
54
54
|
export declare function mergeRouterConfig(base: RouterConfig, override: Partial<RouterConfig>): RouterConfig;
|
|
55
|
+
/**
|
|
56
|
+
* Validate and normalize an on-disk `agentOverrides` map (issue #568).
|
|
57
|
+
*
|
|
58
|
+
* User-hand-edited config is untrusted input: drop entries that name a provider
|
|
59
|
+
* we cannot construct, and strip any `apiKey`-shaped field that leaked in — the
|
|
60
|
+
* same "never persist API keys" discipline `saveRouterConfigFile` already
|
|
61
|
+
* enforces for `providers.*`.
|
|
62
|
+
*
|
|
63
|
+
* Returns the cleaned map plus human-readable warnings for the caller to log.
|
|
64
|
+
* Invalid entries are dropped, never thrown on: a typo in one agent key must not
|
|
65
|
+
* take down router initialization for the whole project.
|
|
66
|
+
*/
|
|
67
|
+
export declare function sanitizeAgentOverrides(raw: unknown): {
|
|
68
|
+
overrides: Record<string, AgentProviderOverride>;
|
|
69
|
+
warnings: string[];
|
|
70
|
+
};
|
|
55
71
|
/**
|
|
56
72
|
* Apply env-detection on top of a merged config: providers whose API
|
|
57
73
|
* keys are present in env are force-enabled (so a user who sets
|