agentic-qe 3.9.7 → 3.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/README.md +4 -3
- package/.claude/skills/a11y-ally/SKILL.md +40 -18
- package/.claude/skills/accessibility-testing/SKILL.md +4 -0
- package/.claude/skills/compatibility-testing/SKILL.md +23 -0
- package/.claude/skills/e2e-flow-verifier/SKILL.md +87 -52
- package/.claude/skills/enterprise-integration-testing/SKILL.md +4 -0
- package/.claude/skills/localization-testing/SKILL.md +14 -0
- package/.claude/skills/observability-testing-patterns/SKILL.md +16 -0
- package/.claude/skills/qe-browser/SKILL.md +409 -0
- package/.claude/skills/qe-browser/evals/qe-browser.yaml +291 -0
- package/.claude/skills/qe-browser/fixtures/package.json +7 -0
- package/.claude/skills/qe-browser/fixtures/serve-skills.js +130 -0
- package/.claude/skills/qe-browser/references/assertion-kinds.md +132 -0
- package/.claude/skills/qe-browser/references/migration-from-playwright.md +195 -0
- package/.claude/skills/qe-browser/schemas/output.json +188 -0
- package/.claude/skills/qe-browser/scripts/assert.js +378 -0
- package/.claude/skills/qe-browser/scripts/batch.js +292 -0
- package/.claude/skills/qe-browser/scripts/check-injection.js +267 -0
- package/.claude/skills/qe-browser/scripts/intent-score.js +325 -0
- package/.claude/skills/qe-browser/scripts/lib/vibium.js +330 -0
- package/.claude/skills/qe-browser/scripts/package.json +7 -0
- package/.claude/skills/qe-browser/scripts/smoke-test.sh +212 -0
- package/.claude/skills/qe-browser/scripts/validate-config.json +46 -0
- package/.claude/skills/qe-browser/scripts/visual-diff.js +276 -0
- package/.claude/skills/qe-visual-accessibility/SKILL.md +31 -1
- package/.claude/skills/security-visual-testing/SKILL.md +18 -0
- package/.claude/skills/skills-manifest.json +20 -13
- package/.claude/skills/testability-scoring/SKILL.md +23 -0
- package/.claude/skills/trust-tier-manifest.json +14 -3
- package/.claude/skills/visual-testing-advanced/SKILL.md +41 -1
- package/CHANGELOG.md +79 -0
- package/README.md +5 -3
- package/assets/skills/README.md +4 -3
- package/assets/skills/a11y-ally/SKILL.md +40 -18
- package/assets/skills/accessibility-testing/SKILL.md +4 -0
- package/assets/skills/compatibility-testing/SKILL.md +23 -0
- package/assets/skills/e2e-flow-verifier/SKILL.md +87 -52
- package/assets/skills/enterprise-integration-testing/SKILL.md +4 -0
- package/assets/skills/localization-testing/SKILL.md +14 -0
- package/assets/skills/observability-testing-patterns/SKILL.md +16 -0
- package/assets/skills/qe-browser/SKILL.md +409 -0
- package/assets/skills/qe-browser/evals/qe-browser.yaml +291 -0
- package/assets/skills/qe-browser/fixtures/package.json +7 -0
- package/assets/skills/qe-browser/fixtures/serve-skills.js +130 -0
- package/assets/skills/qe-browser/references/assertion-kinds.md +132 -0
- package/assets/skills/qe-browser/references/migration-from-playwright.md +195 -0
- package/assets/skills/qe-browser/schemas/output.json +188 -0
- package/assets/skills/qe-browser/scripts/assert.js +378 -0
- package/assets/skills/qe-browser/scripts/batch.js +292 -0
- package/assets/skills/qe-browser/scripts/check-injection.js +267 -0
- package/assets/skills/qe-browser/scripts/intent-score.js +325 -0
- package/assets/skills/qe-browser/scripts/lib/vibium.js +330 -0
- package/assets/skills/qe-browser/scripts/package.json +7 -0
- package/assets/skills/qe-browser/scripts/smoke-test.sh +212 -0
- package/assets/skills/qe-browser/scripts/validate-config.json +46 -0
- package/assets/skills/qe-browser/scripts/visual-diff.js +276 -0
- package/assets/skills/qe-visual-accessibility/SKILL.md +31 -1
- package/assets/skills/security-visual-testing/SKILL.md +18 -0
- package/assets/skills/skills-manifest.json +211 -15
- package/assets/skills/testability-scoring/SKILL.md +23 -0
- package/assets/skills/trust-tier-manifest.json +14 -3
- package/assets/skills/visual-testing-advanced/SKILL.md +41 -1
- package/dist/cli/bundle.js +5 -5
- package/dist/cli/chunks/adapter-XKXEZEMM.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-MXTWTD4D.js → agent-booster-wasm-QEN7W6VC.js} +2 -2
- package/dist/cli/chunks/{agent-handler-6NEP2BOA.js → agent-handler-F3RLG42J.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-SAPEIGE2.js → agent-memory-branch-U3PZ3CPL.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-K7XGBDMZ.js +2 -0
- package/dist/cli/chunks/{audit-53LCI6R3.js → audit-FF6SP7Q2.js} +2 -2
- package/dist/cli/chunks/base-NUF35LIJ.js +2 -0
- package/dist/cli/chunks/{better-sqlite3-UZSKFGCK.js → better-sqlite3-CVXRDGQX.js} +2 -2
- package/dist/cli/chunks/{brain-handler-67NDDXVO.js → brain-handler-AMTRZ35W.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-IUIGYEK5.js → branch-enumerator-Y4A34YFT.js} +2 -2
- package/dist/cli/chunks/{browser-UFUF65LQ.js → browser-ETSF5GZR.js} +2 -2
- package/dist/cli/chunks/browser-workflow-MWPELXFA.js +2 -0
- package/dist/cli/chunks/{chunk-XD4UFF2Y.js → chunk-22HQFULR.js} +1 -1
- package/dist/cli/chunks/{chunk-W4Y4GFRB.js → chunk-2BSVGL35.js} +1 -1
- package/dist/cli/chunks/{chunk-KHH5UJXY.js → chunk-2HFPJPQW.js} +2 -2
- package/dist/cli/chunks/{chunk-LPLCT2HH.js → chunk-2JAYDTSE.js} +2 -2
- package/dist/cli/chunks/{chunk-RGJ4RMUR.js → chunk-2KY5B4ON.js} +8 -8
- package/dist/cli/chunks/{chunk-XB2GVTY6.js → chunk-2O3WZ6E3.js} +1 -1
- package/dist/cli/chunks/{chunk-5EOM3W6Q.js → chunk-2UP3DYNH.js} +2 -2
- package/dist/cli/chunks/{chunk-DS3XAGGL.js → chunk-2X7LDTVD.js} +2 -2
- package/dist/cli/chunks/{chunk-NJ5IC6ZR.js → chunk-2ZHA6ORO.js} +1 -1
- package/dist/cli/chunks/{chunk-FKJ4XZ6E.js → chunk-3F666FYP.js} +2 -2
- package/dist/cli/chunks/{chunk-7TKZ6LK6.js → chunk-3FAEM5M7.js} +1 -1
- package/dist/cli/chunks/{chunk-TLTRL32T.js → chunk-3JCZTTFY.js} +1 -1
- package/dist/cli/chunks/{chunk-BPYWDM2Y.js → chunk-3NU4C62D.js} +3 -3
- package/dist/cli/chunks/{chunk-ZETZATNY.js → chunk-3XR7ARS6.js} +2 -2
- package/dist/cli/chunks/{chunk-FHBIJBZ3.js → chunk-4CDSEZD6.js} +2 -2
- package/dist/cli/chunks/{chunk-OURDPRGM.js → chunk-4CSINHCB.js} +1 -1
- package/dist/cli/chunks/{chunk-YTF5G3RQ.js → chunk-4HDG7OS4.js} +2 -2
- package/dist/cli/chunks/{chunk-PMZJ54WX.js → chunk-52RZZV4M.js} +3 -3
- package/dist/cli/chunks/{chunk-GOG6L2F7.js → chunk-5DU4YW2S.js} +2 -2
- package/dist/cli/chunks/{chunk-6MMRZYYS.js → chunk-5HM66R4W.js} +3 -3
- package/dist/cli/chunks/{chunk-BTZEKSWH.js → chunk-5L3EUZJA.js} +2 -2
- package/dist/cli/chunks/{chunk-TD2WOW75.js → chunk-5SWY75MJ.js} +2 -2
- package/dist/cli/chunks/{chunk-3DXO5CWI.js → chunk-65XCVUP7.js} +1 -1
- package/dist/cli/chunks/{chunk-VMWLVRJO.js → chunk-6KQLF3ZO.js} +2 -2
- package/dist/cli/chunks/{chunk-HVJXXGB4.js → chunk-6LTJP3DO.js} +4 -4
- package/dist/cli/chunks/{chunk-FJEIX3IS.js → chunk-6PJUDLCT.js} +2 -2
- package/dist/cli/chunks/{chunk-2TRWUJWG.js → chunk-74FBSJVC.js} +2 -2
- package/dist/cli/chunks/{chunk-D3KORDD5.js → chunk-A6GYFTIA.js} +1 -1
- package/dist/cli/chunks/{chunk-3KX7CQEM.js → chunk-ADJGMTIW.js} +1 -1
- package/dist/cli/chunks/{chunk-TT2YXNHH.js → chunk-AHOP227C.js} +4 -4
- package/dist/cli/chunks/{chunk-UXCEJ3AV.js → chunk-ANLFEGDG.js} +2 -2
- package/dist/cli/chunks/{chunk-SQQ57TSJ.js → chunk-AT2VD2ZP.js} +2 -2
- package/dist/cli/chunks/{chunk-KLLHSXIC.js → chunk-AYMIF4W5.js} +2 -2
- package/dist/cli/chunks/{chunk-JJSJSQNJ.js → chunk-B3DA4SCL.js} +1 -1
- package/dist/cli/chunks/{chunk-FBVEHGNE.js → chunk-BSES27JE.js} +3 -3
- package/dist/cli/chunks/{chunk-MUEFXLGX.js → chunk-BVKS3X2I.js} +1 -1
- package/dist/cli/chunks/{chunk-MR7V7QVL.js → chunk-BVOGMK6N.js} +2 -2
- package/dist/cli/chunks/{chunk-PHBE2VBN.js → chunk-BYJEK6LX.js} +2 -2
- package/dist/cli/chunks/{chunk-YV2PVXJE.js → chunk-BYPBKVTC.js} +1 -1
- package/dist/cli/chunks/{chunk-IQLFWO5U.js → chunk-C7YD7O74.js} +2 -2
- package/dist/cli/chunks/{chunk-ZEFDSMF4.js → chunk-CCCBGKVY.js} +2 -2
- package/dist/cli/chunks/{chunk-SIIYQLKH.js → chunk-CJQLJEO4.js} +2 -2
- package/dist/cli/chunks/{chunk-AT6LBLUV.js → chunk-CXWA34RL.js} +2 -2
- package/dist/cli/chunks/{chunk-HFPT7QXQ.js → chunk-CZYTPNUI.js} +2 -2
- package/dist/cli/chunks/{chunk-YIVZ5Z4V.js → chunk-DI6R2AVP.js} +1 -1
- package/dist/cli/chunks/{chunk-JNEG6DKU.js → chunk-DNS7DP2O.js} +1 -1
- package/dist/cli/chunks/{chunk-DKBXIBRS.js → chunk-ECNPBD4Y.js} +2 -2
- package/dist/cli/chunks/{chunk-7OPVTN5W.js → chunk-ENG5UF7M.js} +2 -2
- package/dist/cli/chunks/{chunk-EIGXGMOR.js → chunk-EV2NMWJV.js} +1 -1
- package/dist/cli/chunks/{chunk-426OO3RH.js → chunk-FGW5W3YK.js} +2 -2
- package/dist/cli/chunks/{chunk-SMKRBNO7.js → chunk-FTF34UME.js} +1 -1
- package/dist/cli/chunks/{chunk-VAKJOTGU.js → chunk-GYNGJHYF.js} +2 -2
- package/dist/cli/chunks/{chunk-AHB2F42G.js → chunk-HDM43P7H.js} +1 -1
- package/dist/cli/chunks/{chunk-ZWAJV4SN.js → chunk-HOWZFW7G.js} +2 -2
- package/dist/cli/chunks/{chunk-INJPS7RF.js → chunk-IZC5NPHD.js} +1 -1
- package/dist/cli/chunks/{chunk-HEENVPYF.js → chunk-J2DNMVB5.js} +3 -3
- package/dist/cli/chunks/{chunk-SP3X35XC.js → chunk-J62N66ZH.js} +1 -1
- package/dist/cli/chunks/{chunk-QKJ4LUAM.js → chunk-JIPU4YQK.js} +2 -2
- package/dist/cli/chunks/{chunk-4B5IYFKE.js → chunk-JK4K4EH3.js} +2 -2
- package/dist/cli/chunks/{chunk-LP6EQI2P.js → chunk-JQJHRQRX.js} +2 -2
- package/dist/cli/chunks/{chunk-FOCGOVIM.js → chunk-KSJCMXAJ.js} +2 -2
- package/dist/cli/chunks/{chunk-EFHR7LML.js → chunk-MDTF7LE6.js} +2 -2
- package/dist/cli/chunks/{chunk-PFTR6XAO.js → chunk-MUCFC3YG.js} +2 -2
- package/dist/cli/chunks/{chunk-JRHKFRUB.js → chunk-MUIJVPGB.js} +2 -2
- package/dist/cli/chunks/{chunk-WLYSZV5U.js → chunk-MWZN4PYF.js} +2 -2
- package/dist/cli/chunks/{chunk-JZYCZMHN.js → chunk-MXMKHI2I.js} +2 -2
- package/dist/cli/chunks/{chunk-XOHRM3M7.js → chunk-MZOYBHJ3.js} +3 -3
- package/dist/cli/chunks/{chunk-WV3R5JFE.js → chunk-NLKJI73E.js} +2 -2
- package/dist/cli/chunks/{chunk-D2C4XNF5.js → chunk-NQ3WHTLT.js} +4 -4
- package/dist/cli/chunks/{chunk-BJKRAFS2.js → chunk-NVVF5ROM.js} +2 -2
- package/dist/cli/chunks/{chunk-STASZVMY.js → chunk-OEZA7Q2Z.js} +2 -2
- package/dist/cli/chunks/{chunk-LHGZRKPO.js → chunk-OFOFXJ3M.js} +2 -2
- package/dist/cli/chunks/{chunk-2SJQ3CYN.js → chunk-OMRZUYXN.js} +9 -9
- package/dist/cli/chunks/{chunk-KHEAWN23.js → chunk-P6YMECV2.js} +2 -2
- package/dist/cli/chunks/{chunk-ZSXSUUBS.js → chunk-PEEN4AAK.js} +1 -1
- package/dist/cli/chunks/{chunk-6ULPQTIE.js → chunk-PRJUO2OQ.js} +2 -2
- package/dist/cli/chunks/{chunk-ECRYU5XG.js → chunk-PYTXZMXR.js} +2 -2
- package/dist/cli/chunks/{chunk-4NHE7AJE.js → chunk-Q2ZBPOUX.js} +1 -1
- package/dist/cli/chunks/{chunk-XY5FMZRA.js → chunk-QHATTMJC.js} +2 -2
- package/dist/cli/chunks/{chunk-HE5VY2BI.js → chunk-QMNAELZG.js} +2 -2
- package/dist/cli/chunks/{chunk-KZSZHP32.js → chunk-QQLQEQJM.js} +2 -2
- package/dist/cli/chunks/{chunk-7GPYOMVY.js → chunk-QSA23PJ6.js} +1 -1
- package/dist/cli/chunks/{chunk-GGPGY5QT.js → chunk-QTYTM7C7.js} +2 -2
- package/dist/cli/chunks/{chunk-YR5ZNQT2.js → chunk-QZMBJ67L.js} +2 -2
- package/dist/cli/chunks/{chunk-URBXUDY3.js → chunk-R23PJGH7.js} +2 -2
- package/dist/cli/chunks/{chunk-NKX2Z546.js → chunk-R5ZKFJ3H.js} +1 -1
- package/dist/cli/chunks/{chunk-KO5HO6MY.js → chunk-RLLDZNLF.js} +2 -2
- package/dist/cli/chunks/{chunk-ZLQYGO6N.js → chunk-RZYTJSQT.js} +1 -1
- package/dist/cli/chunks/{chunk-ZV7FGZNJ.js → chunk-S6VT7VAO.js} +2 -2
- package/dist/cli/chunks/{chunk-QI5VGEKC.js → chunk-SVLO2DVL.js} +2 -2
- package/dist/cli/chunks/{chunk-SURZYSSL.js → chunk-TTENF6AH.js} +1 -1
- package/dist/cli/chunks/{chunk-6OKXGDT3.js → chunk-UEKDDUGV.js} +2 -2
- package/dist/cli/chunks/{chunk-UEFAPTBV.js → chunk-UYKIPSRX.js} +1 -1
- package/dist/cli/chunks/{chunk-WS4OVAWU.js → chunk-VIIUJRKA.js} +2 -2
- package/dist/cli/chunks/chunk-VRH3YLO2.js +2 -0
- package/dist/cli/chunks/{chunk-YHZWNT45.js → chunk-VTX4NAWB.js} +2 -2
- package/dist/cli/chunks/{chunk-APPVAGD5.js → chunk-VWHALAEO.js} +1 -1
- package/dist/cli/chunks/{chunk-BWNH22V2.js → chunk-W4VDPHWC.js} +1 -1
- package/dist/cli/chunks/{chunk-CDFYF33M.js → chunk-W57I57M4.js} +2 -2
- package/dist/cli/chunks/{chunk-LZ34CKYE.js → chunk-WDWIJDQR.js} +2 -2
- package/dist/cli/chunks/{chunk-W4HUWBPK.js → chunk-WEJJWJ5M.js} +2 -2
- package/dist/cli/chunks/{chunk-A5VULTCD.js → chunk-WZR4CKR4.js} +1 -1
- package/dist/cli/chunks/{chunk-DL46KSFX.js → chunk-XZ2JYMFT.js} +2 -2
- package/dist/cli/chunks/{chunk-WAP7ROO5.js → chunk-YISXT54V.js} +2 -2
- package/dist/cli/chunks/{chunk-HWDE4RB3.js → chunk-YRORPSPA.js} +2 -2
- package/dist/cli/chunks/{chunk-T7R5NXJW.js → chunk-YXE67VME.js} +6 -6
- package/dist/cli/chunks/{chunk-UDBSEFUT.js → chunk-Z7AFNZMI.js} +2 -2
- package/dist/cli/chunks/{chunk-52MUZGZF.js → chunk-ZEUORIH2.js} +2 -2
- package/dist/cli/chunks/{chunk-SQZ3H6WR.js → chunk-ZKXA4VBK.js} +3 -3
- package/dist/cli/chunks/{chunk-EL2WLSUI.js → chunk-ZTI3BATG.js} +2 -2
- package/dist/cli/chunks/{ci-F4F3SDHP.js → ci-4QYE6JBM.js} +2 -2
- package/dist/cli/chunks/{ci-output-4SUMOQGO.js → ci-output-MV75HUK7.js} +2 -2
- package/dist/cli/chunks/{claude-flow-setup-NKXPDFMJ.js → claude-flow-setup-CZITY7SG.js} +2 -2
- package/dist/cli/chunks/client-VXVVUQDV.js +2 -0
- package/dist/cli/chunks/{cline-installer-3FMNXEKM.js → cline-installer-ZLQKCPFF.js} +2 -2
- package/dist/cli/chunks/{code-5QEDZNKI.js → code-NYEXOJVP.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-RD5EAOLE.js → code-index-extractor-TITXUC44.js} +2 -2
- package/dist/cli/chunks/{codex-installer-UU4O2FIE.js → codex-installer-TWT4LIL2.js} +2 -2
- package/dist/cli/chunks/{completions-CS6RJLYZ.js → completions-2KNV2MZG.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-U4DE2QTP.js → complexity-analyzer-2U3OVRDX.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-E55EG2TB.js → continuedev-installer-BWQBRVTC.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-TVJUX3AZ.js → copilot-installer-CYN33NMG.js} +2 -2
- package/dist/cli/chunks/{cost-tracker-IAKDLDJH.js → cost-tracker-2GUCBYLK.js} +2 -2
- package/dist/cli/chunks/{coverage-LX7UIEKV.js → coverage-BAVD66VL.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-HUJG6CFC.js +2 -0
- package/dist/cli/chunks/{cursor-installer-2NJ7MK23.js → cursor-installer-ZQAUD47B.js} +2 -2
- package/dist/cli/chunks/{daemon-T4CPOFHM.js → daemon-VY2LZPIM.js} +3 -3
- package/dist/cli/chunks/{dag-attention-scheduler-GAPYYUHZ.js → dag-attention-scheduler-JNQWWXSW.js} +2 -2
- package/dist/cli/chunks/{detect-RU5LBCCI.js → detect-Y7BBW4LI.js} +2 -2
- package/dist/cli/chunks/{domain-handler-LKPDVPF6.js → domain-handler-473WNSR2.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-Q76ITWBK.js → domain-transfer-R4VK7CRR.js} +2 -2
- package/dist/cli/chunks/dream-QQDRI2EQ.js +2 -0
- package/dist/cli/chunks/esm-node-Y3HIFLTX.js +2 -0
- package/dist/cli/chunks/{eval-TFFIZGTW.js → eval-TJAZGRCM.js} +2 -2
- package/dist/cli/chunks/{fast-paths-V6KA3VWH.js → fast-paths-LMN542IB.js} +2 -2
- package/dist/cli/chunks/{feature-flags-MYSY53UU.js → feature-flags-IMFZ7KED.js} +2 -2
- package/dist/cli/chunks/{feature-flags-DWS4XL2P.js → feature-flags-WMXIDTXL.js} +2 -2
- package/dist/cli/chunks/{file-discovery-AMKZRFLT.js → file-discovery-GXXWQJV3.js} +2 -2
- package/dist/cli/chunks/{fleet-B2BJFKEV.js → fleet-WIC7RHJV.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-SOJHQ7VC.js → gnn-wrapper-PVKCXV25.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-O7FF6NRE.js → heartbeat-handler-BJ6ZZP7Q.js} +4 -4
- package/dist/cli/chunks/{heartbeat-scheduler-WOGW5R7J.js → heartbeat-scheduler-3SQXTFYU.js} +2 -2
- package/dist/cli/chunks/hnsw-adapter-VKS7ORL2.js +2 -0
- package/dist/cli/chunks/hnsw-index-GPUBY6EQ.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-CC5YS47X.js → hnsw-legacy-bridge-23HFWIPK.js} +2 -2
- package/dist/cli/chunks/{hnswlib-node-FTWYRETS.js → hnswlib-node-4GRFMUPD.js} +2 -2
- package/dist/cli/chunks/{hooks-ETOFFBMV.js → hooks-IXH5454I.js} +6 -6
- package/dist/cli/chunks/{hypergraph-engine-FGAHFWFO.js → hypergraph-engine-TEQMJFJJ.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-GNWJD7E3.js → hypergraph-handler-3ECUWIG3.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-D6MBGRKX.js +2 -0
- package/dist/cli/chunks/{init-handler-BEYOLKQO.js → init-handler-TZRKW3NZ.js} +6 -6
- package/dist/cli/chunks/init-wizard-S6P2MFJF.js +2 -0
- package/dist/cli/chunks/kernel-EFDDMNXJ.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-ED6LYSEM.js → kilocode-installer-IPH3O3ZS.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-NG77T5YR.js → kiro-installer-VROMOOQO.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-4PM4DFH3.js +2 -0
- package/dist/cli/chunks/{learning-P3WY3LTI.js → learning-JYQLD66S.js} +3 -3
- package/dist/cli/chunks/{llm-router-ETSFMOWS.js → llm-router-CIICNICY.js} +2 -2
- package/dist/cli/chunks/{load-PP3GVQT7.js → load-DMAQB4NC.js} +2 -2
- package/dist/cli/chunks/load-test-PPSWF3TO.js +2 -0
- package/dist/cli/chunks/{mcp-B2VX7EKL.js → mcp-K6CSUBMU.js} +2 -2
- package/dist/cli/chunks/{memory-SBZQ6MZ4.js → memory-5BSXKHSK.js} +5 -5
- package/dist/cli/chunks/memory-backend-3E6BA2JU.js +2 -0
- package/dist/cli/chunks/{memory-handlers-5RMGG2CR.js → memory-handlers-APOLXPNH.js} +2 -2
- package/dist/cli/chunks/{opencode-installer-PIDIFO2L.js → opencode-installer-IUWO2QV6.js} +2 -2
- package/dist/cli/chunks/{orchestrator-FSGUODZI.js → orchestrator-Z2EM76CR.js} +22 -19
- package/dist/cli/chunks/{pipeline-BQ5MWZPT.js → pipeline-OL5SI2RI.js} +2 -2
- package/dist/cli/chunks/{platform-6EJK4QMD.js → platform-VNJIKIHZ.js} +2 -2
- package/dist/cli/chunks/{plugin-EDGOMUJY.js → plugin-SJJUE47D.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-4S6FYKPP.js → prime-radiant-advanced-wasm-ZLVTCNSH.js} +2 -2
- package/dist/cli/chunks/protocol-executor-2RD52J5J.js +2 -0
- package/dist/cli/chunks/{protocol-handler-ETM7PMQU.js → protocol-handler-HTX44YTW.js} +2 -2
- package/dist/cli/chunks/{prove-YUBORZAP.js → prove-MGFLVZNS.js} +2 -2
- package/dist/cli/chunks/qe-reasoning-bank-OGKT52EN.js +2 -0
- package/dist/cli/chunks/{quality-XPZDC5FJ.js → quality-FMFKPICZ.js} +2 -2
- package/dist/cli/chunks/queen-coordinator-B63YXNI6.js +2 -0
- package/dist/cli/chunks/{real-embeddings-KTDUTUJL.js → real-embeddings-2BMEEOA2.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-WADVKI3P.js → roocode-installer-2PA3B5JI.js} +2 -2
- package/dist/cli/chunks/router-NDQCJQC6.js +2 -0
- package/dist/cli/chunks/routing-feedback-PSN2RLDO.js +2 -0
- package/dist/cli/chunks/{routing-handler-OOPOYHEV.js → routing-handler-SNGSQ757.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-UPEZL4OK.js → ruvector-commands-54MYLF63.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-TOBBCJ7K.js → rvf-dual-writer-6Q44XJOJ.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-U7UM2U36.js → rvf-migration-adapter-JECN625C.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-CUX3EU2X.js → rvf-migration-coordinator-MEAVIHQY.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-F56HQKLS.js +2 -0
- package/dist/cli/chunks/safe-db-LMRMNROL.js +2 -0
- package/dist/cli/chunks/schedule-OZSUYPPC.js +2 -0
- package/dist/cli/chunks/scheduler-GFXCQ6ZA.js +2 -0
- package/dist/cli/chunks/{security-AQ4N5YKV.js → security-CXLXTNIV.js} +3 -3
- package/dist/cli/chunks/shared-rvf-adapter-RZPF4WWK.js +2 -0
- package/dist/cli/chunks/{shared-rvf-dual-writer-OKRIHVSY.js → shared-rvf-dual-writer-SOQDKE6S.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-VP67CJPK.js +2 -0
- package/dist/cli/chunks/{status-handler-HSJLJPNG.js → status-handler-NNEF4SQV.js} +2 -2
- package/dist/cli/chunks/{structural-health-KWZAS7ON.js → structural-health-FY6QIA55.js} +2 -2
- package/dist/cli/chunks/{sync-6L5Z4IWH.js → sync-2QMSZ67Q.js} +2 -2
- package/dist/cli/chunks/{task-handler-KEAIPB6G.js → task-handler-GZJPE2QW.js} +2 -2
- package/dist/cli/chunks/{task-handlers-BPDN6OSM.js → task-handlers-AHM37D4I.js} +2 -2
- package/dist/cli/chunks/{test-PICO6RLU.js → test-JVA2S2R2.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-BI3R3DX5.js → test-scheduling-PRMP4H6X.js} +3 -3
- package/dist/cli/chunks/{token-bootstrap-KMQC6ALU.js → token-bootstrap-YJEHCBV2.js} +2 -2
- package/dist/cli/chunks/{token-usage-QGDX7MLB.js → token-usage-G73L32OF.js} +2 -2
- package/dist/cli/chunks/{transformers-UNRYJSIU.js → transformers-U3TSLEGO.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-U22JYPOG.js → tree-sitter-wasm-parser-QXP2MNSX.js} +2 -2
- package/dist/cli/chunks/{types-CYXAGOY5.js → types-BIQ7O5VR.js} +2 -2
- package/dist/cli/chunks/unified-memory-JB4KPMPI.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-RPSZZIWP.js +2 -0
- package/dist/cli/chunks/unified-persistence-L23T4C5C.js +2 -0
- package/dist/cli/chunks/{validate-IUY5BWAV.js → validate-CTBEA4BZ.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-FXFKSEOI.js → validate-swarm-PHT6XW3A.js} +2 -2
- package/dist/cli/chunks/{vibium-DKZ64NR3.js → vibium-CRCYAH3V.js} +2 -2
- package/dist/cli/chunks/visual-security-F2I524IQ.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-WQDTN5CV.js → web-tree-sitter-2MH3G7K7.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-O5WOBFOQ.js → windsurf-installer-LBRNYFSI.js} +2 -2
- package/dist/cli/chunks/witness-chain-CN6FCWRY.js +2 -0
- package/dist/cli/chunks/{witness-chain-F7WXEVJA.js → witness-chain-HNFQLO7Q.js} +2 -2
- package/dist/cli/chunks/{workflow-47524I5G.js → workflow-DNAF6BQ2.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-JJBCCNYI.js +2 -0
- package/dist/cli/chunks/{wrappers-MP2HWQD7.js → wrappers-U7AO6ZZN.js} +2 -2
- package/dist/init/browser-engine-installer.d.ts +60 -0
- package/dist/init/browser-engine-installer.js +92 -0
- package/dist/init/phases/09-assets.d.ts +2 -0
- package/dist/init/phases/09-assets.js +65 -0
- package/dist/init/skills-installer.js +1 -0
- package/dist/mcp/bundle.js +1 -1
- package/package.json +1 -1
- package/dist/cli/chunks/adapter-GE3RSG32.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-IYL6TK6E.js +0 -2
- package/dist/cli/chunks/base-L3G3GEZY.js +0 -2
- package/dist/cli/chunks/browser-workflow-7KTCY5FI.js +0 -2
- package/dist/cli/chunks/chunk-N5SLJOBK.js +0 -2
- package/dist/cli/chunks/client-3DPPDO2H.js +0 -2
- package/dist/cli/chunks/cross-domain-router-JOYTUBFT.js +0 -2
- package/dist/cli/chunks/dream-IF2HCRW4.js +0 -2
- package/dist/cli/chunks/esm-node-LNRP5BNU.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-UPX4AXOQ.js +0 -2
- package/dist/cli/chunks/hnsw-index-CSI2EXXR.js +0 -2
- package/dist/cli/chunks/impact-analyzer-2YVBHMES.js +0 -2
- package/dist/cli/chunks/init-wizard-V6GZQMMR.js +0 -2
- package/dist/cli/chunks/kernel-EHJ4SP2Y.js +0 -2
- package/dist/cli/chunks/knowledge-graph-ZYXBWGKL.js +0 -2
- package/dist/cli/chunks/load-test-VDZEYGKV.js +0 -2
- package/dist/cli/chunks/memory-backend-IB3BU4VM.js +0 -2
- package/dist/cli/chunks/protocol-executor-H2ZG7JBJ.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-ZCSHSKZU.js +0 -2
- package/dist/cli/chunks/queen-coordinator-NEC373VS.js +0 -2
- package/dist/cli/chunks/router-3PP5XRTD.js +0 -2
- package/dist/cli/chunks/routing-feedback-JNUFV2X3.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-PTOZXG4W.js +0 -2
- package/dist/cli/chunks/safe-db-CGYNYUES.js +0 -2
- package/dist/cli/chunks/schedule-NRN4WOHX.js +0 -2
- package/dist/cli/chunks/scheduler-DRAQGYLL.js +0 -2
- package/dist/cli/chunks/shared-rvf-adapter-6UVVDOHK.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-3WG7PBPL.js +0 -2
- package/dist/cli/chunks/unified-memory-EXRANFUS.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-GB752D44.js +0 -2
- package/dist/cli/chunks/unified-persistence-V2B3YWFD.js +0 -2
- package/dist/cli/chunks/visual-security-YMPI7X7V.js +0 -2
- package/dist/cli/chunks/witness-chain-7LIPUVMI.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-QPIAR4LI.js +0 -2
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// qe-browser: prompt-injection scanner for the current Vibium page.
|
|
3
|
+
//
|
|
4
|
+
// Scans both visible text and optionally hidden/offscreen content for common
|
|
5
|
+
// prompt-injection patterns that might try to manipulate an LLM browsing the page.
|
|
6
|
+
// Pattern library ported from gsd-browser (MIT/Apache-2.0) with extensions.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// node check-injection.js
|
|
10
|
+
// node check-injection.js --include-hidden
|
|
11
|
+
// node check-injection.js --json
|
|
12
|
+
// node check-injection.js --exclude-selector "main, .docs-content"
|
|
13
|
+
//
|
|
14
|
+
// M8 (devil's-advocate finding): the regex patterns match anywhere in the
|
|
15
|
+
// page, including legitimate documentation that talks ABOUT prompt injection.
|
|
16
|
+
// `--exclude-selector` lets callers drop subtrees from the scan (typically
|
|
17
|
+
// used to exclude documentation/markdown bodies on docs sites). Pass a CSS
|
|
18
|
+
// selector list — every matched element's text is removed before scanning.
|
|
19
|
+
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
vibiumEvalStdin,
|
|
24
|
+
envelope,
|
|
25
|
+
parseArgs,
|
|
26
|
+
emit,
|
|
27
|
+
fail,
|
|
28
|
+
runOrSkip,
|
|
29
|
+
rethrowIfUnavailable,
|
|
30
|
+
} = require('./lib/vibium');
|
|
31
|
+
|
|
32
|
+
// Pattern list — each entry: { name, severity, regex, description }.
|
|
33
|
+
// Severities: info < low < medium < high < critical.
|
|
34
|
+
const PATTERNS = [
|
|
35
|
+
{
|
|
36
|
+
name: 'ignore_previous_instructions',
|
|
37
|
+
severity: 'high',
|
|
38
|
+
regex: /ignore\s+(all\s+)?(previous|prior|above|preceding)\s+(instructions|prompts|commands|directives)/i,
|
|
39
|
+
description: 'Classic prompt override',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'new_instructions',
|
|
43
|
+
severity: 'high',
|
|
44
|
+
regex: /(new|updated|revised)\s+(instructions|system\s+prompt|directives)/i,
|
|
45
|
+
description: 'Attempts to inject a new instruction set',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'system_prompt_leak',
|
|
49
|
+
severity: 'critical',
|
|
50
|
+
regex: /\b(show|reveal|print|output|display|repeat|share)\s+(me\s+|us\s+)?(your\s+|the\s+)?(system\s+)?(prompt|instructions|rules|guidelines)\b/i,
|
|
51
|
+
description: 'Attempts to exfiltrate system prompt',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'role_override',
|
|
55
|
+
severity: 'high',
|
|
56
|
+
regex: /you\s+are\s+(now|actually)\s+(a|an)\s+[a-z]+/i,
|
|
57
|
+
description: 'Role reassignment attempt',
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'developer_mode',
|
|
61
|
+
severity: 'high',
|
|
62
|
+
regex: /(enable|activate|enter)\s+(developer|dev|debug|jailbreak|admin|root)\s+mode/i,
|
|
63
|
+
description: 'Developer/jailbreak mode request',
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'confidential_exfil',
|
|
67
|
+
severity: 'critical',
|
|
68
|
+
regex: /(send|post|leak|exfiltrate|upload|forward)\s+.*(api[_\s-]?key|password|secret|token|credential)/i,
|
|
69
|
+
description: 'Credential exfiltration attempt',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
name: 'base64_directive',
|
|
73
|
+
severity: 'medium',
|
|
74
|
+
regex: /decode\s+(the\s+)?(following\s+)?base64\s+(and\s+(run|execute|follow))?/i,
|
|
75
|
+
description: 'Base64-obfuscated instructions',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
name: 'dan_pattern',
|
|
79
|
+
severity: 'high',
|
|
80
|
+
regex: /do\s+anything\s+now|dan\s+(mode|jailbreak|prompt)/i,
|
|
81
|
+
description: 'DAN (Do Anything Now) jailbreak',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
name: 'chain_of_trust',
|
|
85
|
+
severity: 'medium',
|
|
86
|
+
regex: /(this\s+is\s+anthropic|i\s+am\s+a\s+trusted|authorized\s+by\s+the\s+developer)/i,
|
|
87
|
+
description: 'False authority / impersonation',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'exfil_via_url',
|
|
91
|
+
severity: 'high',
|
|
92
|
+
regex: /fetch\s*\(\s*['"`]https?:\/\/[^'"`]*\?(key|secret|token|data)=/i,
|
|
93
|
+
description: 'URL-based data exfiltration',
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
name: 'markdown_image_exfil',
|
|
97
|
+
severity: 'high',
|
|
98
|
+
regex: /!\[[^\]]*\]\(https?:\/\/[^)]+\?[^)]*=[^)]+\)/i,
|
|
99
|
+
description: 'Markdown image exfiltration channel',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
name: 'tool_hijack',
|
|
103
|
+
severity: 'high',
|
|
104
|
+
regex: /(call|invoke|run|execute)\s+(the\s+)?(tool|function|command)\s*:?\s*['"`]?(bash|exec|shell|eval)/i,
|
|
105
|
+
description: 'Tool-use hijacking',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'memory_poison',
|
|
109
|
+
severity: 'medium',
|
|
110
|
+
regex: /remember\s+(this|that)\s+.*(forever|permanently|always)/i,
|
|
111
|
+
description: 'Attempts to poison persistent memory',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'instructions_in_html_comment',
|
|
115
|
+
severity: 'medium',
|
|
116
|
+
regex: /<!--\s*(instructions|system|prompt|note\s+to\s+ai|claude|gpt|llm)/i,
|
|
117
|
+
description: 'Instructions hidden in HTML comments',
|
|
118
|
+
},
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
// M4 (devil's-advocate finding): scanned page text can contain ANSI escape
|
|
122
|
+
// sequences, NUL bytes, or other terminal-control characters. Embedding
|
|
123
|
+
// those verbatim in the JSON snippet means a `cat findings.json` could
|
|
124
|
+
// reposition the cursor, change colors, or trigger terminal exploits. We
|
|
125
|
+
// strip C0 controls (0x00-0x1F except \t \n) and DEL (0x7F) before emitting.
|
|
126
|
+
// We deliberately keep \t and \n so multi-line snippets remain readable.
|
|
127
|
+
function sanitizeSnippet(text) {
|
|
128
|
+
// eslint-disable-next-line no-control-regex
|
|
129
|
+
return text.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function scanText(text, hidden) {
|
|
133
|
+
const findings = [];
|
|
134
|
+
for (const pat of PATTERNS) {
|
|
135
|
+
const match = text.match(pat.regex);
|
|
136
|
+
if (match) {
|
|
137
|
+
const idx = match.index || 0;
|
|
138
|
+
const start = Math.max(0, idx - 40);
|
|
139
|
+
const end = Math.min(text.length, idx + match[0].length + 40);
|
|
140
|
+
const rawSnippet = text.slice(start, end).replace(/\s+/g, ' ').trim();
|
|
141
|
+
findings.push({
|
|
142
|
+
pattern: pat.name,
|
|
143
|
+
severity: pat.severity,
|
|
144
|
+
description: pat.description,
|
|
145
|
+
snippet: sanitizeSnippet(rawSnippet),
|
|
146
|
+
hidden,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return findings;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function aggregateSeverity(findings) {
|
|
154
|
+
const order = { info: 1, low: 2, medium: 3, high: 4, critical: 5 };
|
|
155
|
+
let top = 'none';
|
|
156
|
+
let topRank = 0;
|
|
157
|
+
for (const f of findings) {
|
|
158
|
+
const rank = order[f.severity] || 0;
|
|
159
|
+
if (rank > topRank) {
|
|
160
|
+
topRank = rank;
|
|
161
|
+
top = f.severity;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return top;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function fetchPageText(includeHidden, excludeSelector) {
|
|
168
|
+
// Return both visible and (optionally) full text-content via vibium eval.
|
|
169
|
+
// We pull both so we can tag findings with `hidden: true/false`.
|
|
170
|
+
//
|
|
171
|
+
// H2 (devil's-advocate finding): TreeWalker(SHOW_COMMENT) yields the
|
|
172
|
+
// INNER text of each comment, stripping the `<!-- ... -->` delimiters.
|
|
173
|
+
// The `instructions_in_html_comment` regex requires the literal `<!--`
|
|
174
|
+
// prefix, so it could never fire against the unwrapped text. Fix: re-wrap
|
|
175
|
+
// each comment in `<!-- ... -->` before adding it to the hidden bucket so
|
|
176
|
+
// the comment-pattern actually matches.
|
|
177
|
+
//
|
|
178
|
+
// M8 (devil's-advocate finding): excludeSelector lets callers strip
|
|
179
|
+
// subtrees (typically documentation bodies) from BOTH the visible and
|
|
180
|
+
// hidden text before scanning, so docs about prompt injection don't
|
|
181
|
+
// self-flag. We clone the body, remove matching elements, and read text
|
|
182
|
+
// from the clone — leaving the live page unchanged.
|
|
183
|
+
//
|
|
184
|
+
// Vibium eval returns the LAST EXPRESSION's value, not console.log
|
|
185
|
+
// output, so we wrap our payload in JSON.stringify and let
|
|
186
|
+
// lib/vibium.js's unwrapEvalResult parse it back into an object.
|
|
187
|
+
const excludeJson = excludeSelector ? JSON.stringify(excludeSelector) : 'null';
|
|
188
|
+
const script = `
|
|
189
|
+
(function() {
|
|
190
|
+
var body = document.body;
|
|
191
|
+
var excludeSel = ${excludeJson};
|
|
192
|
+
var workBody = body;
|
|
193
|
+
if (excludeSel && body) {
|
|
194
|
+
workBody = body.cloneNode(true);
|
|
195
|
+
try {
|
|
196
|
+
var toRemove = workBody.querySelectorAll(excludeSel);
|
|
197
|
+
for (var i = 0; i < toRemove.length; i++) {
|
|
198
|
+
toRemove[i].parentNode && toRemove[i].parentNode.removeChild(toRemove[i]);
|
|
199
|
+
}
|
|
200
|
+
} catch (e) { /* invalid selector — fall back to full body */ }
|
|
201
|
+
}
|
|
202
|
+
var visible = workBody ? workBody.innerText : '';
|
|
203
|
+
var full = workBody ? workBody.textContent : '';
|
|
204
|
+
var comments = [];
|
|
205
|
+
var walker = document.createTreeWalker(workBody || document, NodeFilter.SHOW_COMMENT, null);
|
|
206
|
+
var n;
|
|
207
|
+
while ((n = walker.nextNode())) {
|
|
208
|
+
comments.push('<!-- ' + n.textContent + ' -->');
|
|
209
|
+
}
|
|
210
|
+
var hidden = ${includeHidden ? 'full.replace(visible, "") + "\\n" + comments.join("\\n")' : '""'};
|
|
211
|
+
return JSON.stringify({ visible: visible, hidden: hidden });
|
|
212
|
+
})()
|
|
213
|
+
`;
|
|
214
|
+
return vibiumEvalStdin(script) || { visible: '', hidden: '' };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function main() {
|
|
218
|
+
const args = parseArgs(process.argv.slice(2));
|
|
219
|
+
const includeHidden = Boolean(args['include-hidden']);
|
|
220
|
+
// M8: --exclude-selector takes a CSS selector list; matching elements are
|
|
221
|
+
// dropped from the scan so docs about prompt injection don't self-flag.
|
|
222
|
+
const excludeSelector =
|
|
223
|
+
typeof args['exclude-selector'] === 'string' ? args['exclude-selector'] : null;
|
|
224
|
+
const startedAt = Date.now();
|
|
225
|
+
|
|
226
|
+
try {
|
|
227
|
+
const { visible, hidden } = fetchPageText(includeHidden, excludeSelector);
|
|
228
|
+
const findings = [
|
|
229
|
+
...scanText(visible || '', false),
|
|
230
|
+
...scanText(hidden || '', true),
|
|
231
|
+
];
|
|
232
|
+
const severity = findings.length === 0 ? 'none' : aggregateSeverity(findings);
|
|
233
|
+
const status =
|
|
234
|
+
severity === 'none' || severity === 'info' || severity === 'low' ? 'success' : 'failed';
|
|
235
|
+
|
|
236
|
+
return emit(
|
|
237
|
+
envelope({
|
|
238
|
+
operation: 'check-injection',
|
|
239
|
+
summary:
|
|
240
|
+
findings.length === 0
|
|
241
|
+
? 'No prompt-injection patterns detected'
|
|
242
|
+
: `Detected ${findings.length} prompt-injection pattern(s), highest severity: ${severity}`,
|
|
243
|
+
status,
|
|
244
|
+
details: {
|
|
245
|
+
checkInjection: {
|
|
246
|
+
findings,
|
|
247
|
+
severity,
|
|
248
|
+
scanned: {
|
|
249
|
+
visibleChars: (visible || '').length,
|
|
250
|
+
hiddenChars: (hidden || '').length,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
metadata: { executionTimeMs: Date.now() - startedAt },
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
} catch (err) {
|
|
258
|
+
rethrowIfUnavailable(err); // F1: bubble missing-vibium past this catch
|
|
259
|
+
return fail('check-injection', err.message);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (require.main === module) {
|
|
264
|
+
process.exit(runOrSkip('check-injection', main));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
module.exports = { scanText, PATTERNS, aggregateSeverity, sanitizeSnippet };
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// qe-browser: semantic intent scoring for the current Vibium page.
|
|
3
|
+
//
|
|
4
|
+
// Ported from gsd-browser (MIT/Apache-2.0) — the scorer is pure JS heuristic,
|
|
5
|
+
// no LLM round-trip. We push the whole scoring function into `vibium eval --stdin`
|
|
6
|
+
// which runs it in the page context via WebDriver BiDi.
|
|
7
|
+
//
|
|
8
|
+
// Usage:
|
|
9
|
+
// node intent-score.js --intent submit_form
|
|
10
|
+
// node intent-score.js --intent accept_cookies --scope "#banner"
|
|
11
|
+
// node intent-score.js --intent fill_email
|
|
12
|
+
|
|
13
|
+
'use strict';
|
|
14
|
+
|
|
15
|
+
const {
|
|
16
|
+
vibiumEvalStdin,
|
|
17
|
+
envelope,
|
|
18
|
+
parseArgs,
|
|
19
|
+
emit,
|
|
20
|
+
fail,
|
|
21
|
+
runOrSkip,
|
|
22
|
+
rethrowIfUnavailable,
|
|
23
|
+
} = require('./lib/vibium');
|
|
24
|
+
|
|
25
|
+
const VALID_INTENTS = [
|
|
26
|
+
'submit_form',
|
|
27
|
+
'close_dialog',
|
|
28
|
+
'primary_cta',
|
|
29
|
+
'search_field',
|
|
30
|
+
'next_step',
|
|
31
|
+
'dismiss',
|
|
32
|
+
'auth_action',
|
|
33
|
+
'back_navigation',
|
|
34
|
+
'fill_email',
|
|
35
|
+
'fill_password',
|
|
36
|
+
'fill_username',
|
|
37
|
+
'accept_cookies',
|
|
38
|
+
'main_content',
|
|
39
|
+
'pagination_next',
|
|
40
|
+
'pagination_prev',
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
// The scoring function is a self-contained IIFE that runs in the page context.
|
|
44
|
+
// Derived from gsd-browser/cli/src/daemon/handlers/intent.rs:59-385.
|
|
45
|
+
const SCORER_JS = `
|
|
46
|
+
(function () {
|
|
47
|
+
const intent = __INTENT__;
|
|
48
|
+
const scopeSel = __SCOPE__;
|
|
49
|
+
const root = scopeSel ? document.querySelector(scopeSel) : document;
|
|
50
|
+
if (!root) throw new Error('scope element not found: ' + scopeSel);
|
|
51
|
+
|
|
52
|
+
const interactiveSel =
|
|
53
|
+
'a, button, input, select, textarea, [role=button], [role=link], [role=menuitem], ' +
|
|
54
|
+
'[role=tab], [role=search], [role=searchbox], [tabindex], [onclick]';
|
|
55
|
+
const contentSel = 'main, article, section, [role=main], [role=article], div';
|
|
56
|
+
const sel = intent === 'main_content' ? interactiveSel + ', ' + contentSel : interactiveSel;
|
|
57
|
+
const candidates = Array.from(root.querySelectorAll(sel));
|
|
58
|
+
|
|
59
|
+
function isVisible(el) {
|
|
60
|
+
if (el.hidden || el.disabled) return false;
|
|
61
|
+
const rect = el.getBoundingClientRect();
|
|
62
|
+
if (rect.width === 0 && rect.height === 0) return false;
|
|
63
|
+
const style = getComputedStyle(el);
|
|
64
|
+
if (style.display === 'none' || style.visibility === 'hidden' || parseFloat(style.opacity) === 0) return false;
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function getText(el) { return (el.textContent || '').trim().substring(0, 100).toLowerCase(); }
|
|
68
|
+
function getAriaLabel(el) { return (el.getAttribute('aria-label') || '').toLowerCase(); }
|
|
69
|
+
function getRole(el) { return (el.getAttribute('role') || '').toLowerCase(); }
|
|
70
|
+
|
|
71
|
+
function buildSelector(el) {
|
|
72
|
+
if (el.id) return '#' + CSS.escape(el.id);
|
|
73
|
+
const tag = el.tagName.toLowerCase();
|
|
74
|
+
const testId = el.getAttribute('data-testid');
|
|
75
|
+
if (testId) return tag + '[data-testid=' + JSON.stringify(testId) + ']';
|
|
76
|
+
if (el.name) {
|
|
77
|
+
const nsel = tag + '[name=' + JSON.stringify(el.name) + ']';
|
|
78
|
+
if (document.querySelectorAll(nsel).length === 1) return nsel;
|
|
79
|
+
}
|
|
80
|
+
if (el.type) {
|
|
81
|
+
const tsel = tag + '[type=' + JSON.stringify(el.type) + ']';
|
|
82
|
+
if (document.querySelectorAll(tsel).length === 1) return tsel;
|
|
83
|
+
}
|
|
84
|
+
const all = Array.from(document.querySelectorAll(tag));
|
|
85
|
+
const idx = all.indexOf(el);
|
|
86
|
+
return tag + ':nth-of-type(' + (idx + 1) + ')';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const scorers = {
|
|
90
|
+
submit_form(el, tag, type, text, role, aria) {
|
|
91
|
+
let s = 0; const r = [];
|
|
92
|
+
if (type === 'submit') { s += 0.5; r.push('type=submit'); }
|
|
93
|
+
if (tag === 'button' && !el.type) { s += 0.2; r.push('button no-type'); }
|
|
94
|
+
if (/submit|send|save|confirm|create|register|sign.?up|log.?in|continue|next|apply|ok/i.test(text || el.value || aria)) { s += 0.3; r.push('submit text'); }
|
|
95
|
+
if (el.closest('form')) { s += 0.15; r.push('inside form'); }
|
|
96
|
+
if (role === 'button') { s += 0.05; r.push('role=button'); }
|
|
97
|
+
return { score: s, reasons: r };
|
|
98
|
+
},
|
|
99
|
+
close_dialog(el, tag, type, text, role, aria) {
|
|
100
|
+
let s = 0; const r = [];
|
|
101
|
+
// M7: anchor bare 'x' with word boundaries so we don't match
|
|
102
|
+
// "fix", "exit", "extra", "sixteen". The unicode multiplication
|
|
103
|
+
// sign (U+00D7) and small x (U+2715) are unaffected.
|
|
104
|
+
if (/close|dismiss|cancel|\\u00d7|\\u2715|\\bx\\b/i.test(text || aria)) { s += 0.4; r.push('close text'); }
|
|
105
|
+
if (el.closest('dialog, [role=dialog], [role=alertdialog], .modal')) { s += 0.3; r.push('in dialog'); }
|
|
106
|
+
if (aria && /close|dismiss/i.test(aria)) { s += 0.2; r.push('aria close'); }
|
|
107
|
+
if (tag === 'button') { s += 0.05; r.push('is button'); }
|
|
108
|
+
return { score: s, reasons: r };
|
|
109
|
+
},
|
|
110
|
+
primary_cta(el, tag, type, text, role, aria) {
|
|
111
|
+
let s = 0; const r = [];
|
|
112
|
+
if (tag === 'button' || tag === 'a' || role === 'button') { s += 0.15; r.push('interactive'); }
|
|
113
|
+
const rect = el.getBoundingClientRect();
|
|
114
|
+
if (rect.width * rect.height > 3000) { s += 0.15; r.push('large area'); }
|
|
115
|
+
const style = getComputedStyle(el);
|
|
116
|
+
const bg = style.backgroundColor;
|
|
117
|
+
if (bg && bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent') { s += 0.2; r.push('has bg'); }
|
|
118
|
+
if (/get.?started|sign.?up|try|buy|subscribe|download|start|learn.?more/i.test(text || aria)) { s += 0.3; r.push('CTA text'); }
|
|
119
|
+
return { score: s, reasons: r };
|
|
120
|
+
},
|
|
121
|
+
search_field(el, tag, type, text, role, aria) {
|
|
122
|
+
let s = 0; const r = [];
|
|
123
|
+
if (role === 'search' || role === 'searchbox') { s += 0.5; r.push('search role'); }
|
|
124
|
+
if (type === 'search') { s += 0.5; r.push('type=search'); }
|
|
125
|
+
if (tag === 'input' && /search/i.test(aria || el.placeholder || el.name || '')) { s += 0.4; r.push('search attr'); }
|
|
126
|
+
if (tag === 'input' || tag === 'textarea') { s += 0.05; r.push('is input'); }
|
|
127
|
+
return { score: s, reasons: r };
|
|
128
|
+
},
|
|
129
|
+
next_step(el, tag, type, text, role, aria) {
|
|
130
|
+
let s = 0; const r = [];
|
|
131
|
+
if (/next|continue|proceed|forward|\\u2192|\\u203a|>>|step/i.test(text || aria)) { s += 0.4; r.push('next text'); }
|
|
132
|
+
if (tag === 'button' || role === 'button') { s += 0.15; r.push('is button'); }
|
|
133
|
+
if (type === 'submit') { s += 0.1; r.push('type=submit'); }
|
|
134
|
+
return { score: s, reasons: r };
|
|
135
|
+
},
|
|
136
|
+
dismiss(el, tag, type, text, role, aria) {
|
|
137
|
+
let s = 0; const r = [];
|
|
138
|
+
if (/dismiss|close|cancel|no.?thanks|skip|later|not.?now|got.?it|ok|accept/i.test(text || aria)) { s += 0.4; r.push('dismiss text'); }
|
|
139
|
+
if (el.closest('[class*=overlay], [class*=popup], [class*=banner], [class*=toast], [class*=notification]')) { s += 0.2; r.push('in overlay'); }
|
|
140
|
+
if (tag === 'button') { s += 0.1; r.push('is button'); }
|
|
141
|
+
return { score: s, reasons: r };
|
|
142
|
+
},
|
|
143
|
+
auth_action(el, tag, type, text, role, aria) {
|
|
144
|
+
let s = 0; const r = [];
|
|
145
|
+
if (/log.?in|sign.?in|sign.?up|register|auth|sso|forgot.?password/i.test(text || aria)) { s += 0.4; r.push('auth text'); }
|
|
146
|
+
if (type === 'submit' && el.closest('form')) {
|
|
147
|
+
const form = el.closest('form');
|
|
148
|
+
if (form.querySelector('input[type=password]')) { s += 0.3; r.push('has password'); }
|
|
149
|
+
}
|
|
150
|
+
if (tag === 'button' || tag === 'a') { s += 0.1; r.push('interactive'); }
|
|
151
|
+
return { score: s, reasons: r };
|
|
152
|
+
},
|
|
153
|
+
back_navigation(el, tag, type, text, role, aria) {
|
|
154
|
+
let s = 0; const r = [];
|
|
155
|
+
if (/back|previous|\\u2190|\\u2039|<<|return|go.?back/i.test(text || aria)) { s += 0.4; r.push('back text'); }
|
|
156
|
+
if (tag === 'a' && el.href) {
|
|
157
|
+
try {
|
|
158
|
+
const url = new URL(el.href);
|
|
159
|
+
if (url.pathname.length < location.pathname.length) { s += 0.2; r.push('shorter path'); }
|
|
160
|
+
} catch (e) {}
|
|
161
|
+
}
|
|
162
|
+
if (role === 'navigation' || el.closest('nav')) { s += 0.1; r.push('in nav'); }
|
|
163
|
+
return { score: s, reasons: r };
|
|
164
|
+
},
|
|
165
|
+
fill_email(el, tag, type, text, role, aria) {
|
|
166
|
+
let s = 0; const r = [];
|
|
167
|
+
if (type === 'email') { s += 0.6; r.push('type=email'); }
|
|
168
|
+
if (/email|e-mail/i.test(el.name || el.placeholder || aria || '')) { s += 0.4; r.push('email attr'); }
|
|
169
|
+
if (el.autocomplete === 'email') { s += 0.3; r.push('autocomplete=email'); }
|
|
170
|
+
if (tag === 'input') { s += 0.05; r.push('is input'); }
|
|
171
|
+
return { score: s, reasons: r };
|
|
172
|
+
},
|
|
173
|
+
fill_password(el, tag, type, text, role, aria) {
|
|
174
|
+
let s = 0; const r = [];
|
|
175
|
+
if (type === 'password') { s += 0.7; r.push('type=password'); }
|
|
176
|
+
if (/password|passwd|pass/i.test(el.name || el.placeholder || aria || '')) { s += 0.3; r.push('password attr'); }
|
|
177
|
+
if (el.autocomplete === 'current-password' || el.autocomplete === 'new-password') { s += 0.2; r.push('autocomplete=password'); }
|
|
178
|
+
return { score: s, reasons: r };
|
|
179
|
+
},
|
|
180
|
+
fill_username(el, tag, type, text, role, aria) {
|
|
181
|
+
let s = 0; const r = [];
|
|
182
|
+
if (/user.?name|login|account/i.test(el.name || el.placeholder || aria || '')) { s += 0.5; r.push('username attr'); }
|
|
183
|
+
if (el.autocomplete === 'username') { s += 0.4; r.push('autocomplete=username'); }
|
|
184
|
+
if (type === 'text' && el.closest('form')) {
|
|
185
|
+
if (el.closest('form').querySelector('input[type=password]')) { s += 0.2; r.push('text in login form'); }
|
|
186
|
+
}
|
|
187
|
+
if (tag === 'input') { s += 0.05; r.push('is input'); }
|
|
188
|
+
return { score: s, reasons: r };
|
|
189
|
+
},
|
|
190
|
+
accept_cookies(el, tag, type, text, role, aria) {
|
|
191
|
+
let s = 0; const r = [];
|
|
192
|
+
if (/accept|agree|consent|allow|got.?it|ok|i.?understand/i.test(text || aria)) { s += 0.3; r.push('accept text'); }
|
|
193
|
+
if (/cookie/i.test(text || aria)) { s += 0.2; r.push('mentions cookies'); }
|
|
194
|
+
if (el.closest('[class*=cookie], [class*=consent], [class*=gdpr], [class*=privacy], [id*=cookie], [id*=consent]')) { s += 0.3; r.push('in cookie banner'); }
|
|
195
|
+
if (tag === 'button' || role === 'button') { s += 0.1; r.push('is button'); }
|
|
196
|
+
if (/reject|decline|settings|manage|customize/i.test(text || aria)) { s -= 0.3; r.push('reject penalty'); }
|
|
197
|
+
return { score: s, reasons: r };
|
|
198
|
+
},
|
|
199
|
+
main_content(el, tag, type, text, role, aria) {
|
|
200
|
+
let s = 0; const r = [];
|
|
201
|
+
if (role === 'main') { s += 0.6; r.push('role=main'); }
|
|
202
|
+
if (tag === 'main') { s += 0.6; r.push('<main>'); }
|
|
203
|
+
if (tag === 'article') { s += 0.4; r.push('<article>'); }
|
|
204
|
+
if (el.id && /content|main|article|body/i.test(el.id)) { s += 0.3; r.push('content id'); }
|
|
205
|
+
if (el.className && /content|main|article|body/i.test(el.className)) { s += 0.2; r.push('content class'); }
|
|
206
|
+
const rect = el.getBoundingClientRect();
|
|
207
|
+
if (rect.width > 500 && rect.height > 300) { s += 0.15; r.push('large area'); }
|
|
208
|
+
return { score: s, reasons: r };
|
|
209
|
+
},
|
|
210
|
+
pagination_next(el, tag, type, text, role, aria) {
|
|
211
|
+
let s = 0; const r = [];
|
|
212
|
+
if (/next|\\u203a|>>|\\u2192|older/i.test(text || aria)) { s += 0.4; r.push('next text'); }
|
|
213
|
+
if (el.rel === 'next') { s += 0.5; r.push('rel=next'); }
|
|
214
|
+
if (el.closest('nav, [role=navigation], [class*=paginat], [class*=pager]')) { s += 0.2; r.push('in pagination'); }
|
|
215
|
+
if (tag === 'a' || tag === 'button') { s += 0.05; r.push('interactive'); }
|
|
216
|
+
return { score: s, reasons: r };
|
|
217
|
+
},
|
|
218
|
+
pagination_prev(el, tag, type, text, role, aria) {
|
|
219
|
+
let s = 0; const r = [];
|
|
220
|
+
if (/prev|previous|\\u2039|<<|\\u2190|newer/i.test(text || aria)) { s += 0.4; r.push('prev text'); }
|
|
221
|
+
if (el.rel === 'prev') { s += 0.5; r.push('rel=prev'); }
|
|
222
|
+
if (el.closest('nav, [role=navigation], [class*=paginat], [class*=pager]')) { s += 0.2; r.push('in pagination'); }
|
|
223
|
+
if (tag === 'a' || tag === 'button') { s += 0.05; r.push('interactive'); }
|
|
224
|
+
return { score: s, reasons: r };
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const scorer = scorers[intent];
|
|
229
|
+
if (!scorer) throw new Error('unknown intent: ' + intent + '. Valid: ' + Object.keys(scorers).join(', '));
|
|
230
|
+
|
|
231
|
+
const scored = [];
|
|
232
|
+
for (const el of candidates) {
|
|
233
|
+
if (!isVisible(el)) continue;
|
|
234
|
+
const tag = el.tagName.toLowerCase();
|
|
235
|
+
const type = (el.getAttribute('type') || '').toLowerCase();
|
|
236
|
+
const text = getText(el);
|
|
237
|
+
const role = getRole(el);
|
|
238
|
+
const aria = getAriaLabel(el);
|
|
239
|
+
const { score, reasons } = scorer(el, tag, type, text, role, aria);
|
|
240
|
+
if (score <= 0) continue;
|
|
241
|
+
const rect = el.getBoundingClientRect();
|
|
242
|
+
scored.push({
|
|
243
|
+
score: Math.round(score * 1000) / 1000,
|
|
244
|
+
selector: buildSelector(el),
|
|
245
|
+
tag,
|
|
246
|
+
type: type || null,
|
|
247
|
+
role: role || null,
|
|
248
|
+
text: (el.textContent || '').trim().substring(0, 80) || null,
|
|
249
|
+
reason: reasons.join(', '),
|
|
250
|
+
bounds: {
|
|
251
|
+
x: Math.round(rect.x),
|
|
252
|
+
y: Math.round(rect.y),
|
|
253
|
+
width: Math.round(rect.width),
|
|
254
|
+
height: Math.round(rect.height),
|
|
255
|
+
},
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
scored.sort((a, b) => b.score - a.score);
|
|
260
|
+
return {
|
|
261
|
+
intent: intent,
|
|
262
|
+
candidateCount: scored.length,
|
|
263
|
+
candidates: scored.slice(0, 5),
|
|
264
|
+
scope: scopeSel || 'document',
|
|
265
|
+
};
|
|
266
|
+
})()
|
|
267
|
+
`;
|
|
268
|
+
|
|
269
|
+
function buildScript(intent, scope) {
|
|
270
|
+
const intentJson = JSON.stringify(intent);
|
|
271
|
+
const scopeJson = scope ? JSON.stringify(scope) : 'null';
|
|
272
|
+
// Use split/join instead of String.prototype.replace because the second
|
|
273
|
+
// argument of .replace is a *replacement string* where $&, $`, $', $1-$9
|
|
274
|
+
// have special meaning. JSON.stringify output can contain those sequences
|
|
275
|
+
// (e.g. a selector like `div[data-x="$amount"]`) which would otherwise
|
|
276
|
+
// corrupt the generated script. split/join does a literal substitution.
|
|
277
|
+
const body = SCORER_JS.split('__INTENT__').join(intentJson).split('__SCOPE__').join(scopeJson);
|
|
278
|
+
// Vibium eval returns the last expression's value, not console.log output.
|
|
279
|
+
// Wrap in JSON.stringify so lib/vibium.js's unwrapEvalResult can JSON-parse
|
|
280
|
+
// the result string back into a real object on our side.
|
|
281
|
+
return `JSON.stringify(${body})`;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function main() {
|
|
285
|
+
const args = parseArgs(process.argv.slice(2));
|
|
286
|
+
const intent = args.intent;
|
|
287
|
+
if (!intent) return fail('intent-score', 'missing --intent argument');
|
|
288
|
+
if (!VALID_INTENTS.includes(intent)) {
|
|
289
|
+
return fail(
|
|
290
|
+
'intent-score',
|
|
291
|
+
`unknown intent "${intent}". Valid: ${VALID_INTENTS.join(', ')}`
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
const scope = args.scope;
|
|
295
|
+
const startedAt = Date.now();
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
const payload = vibiumEvalStdin(buildScript(intent, scope));
|
|
299
|
+
if (!payload || !Array.isArray(payload.candidates)) {
|
|
300
|
+
throw new Error('scorer returned unexpected payload');
|
|
301
|
+
}
|
|
302
|
+
const top = payload.candidates[0];
|
|
303
|
+
return emit(
|
|
304
|
+
envelope({
|
|
305
|
+
operation: 'intent-score',
|
|
306
|
+
summary:
|
|
307
|
+
payload.candidateCount > 0
|
|
308
|
+
? `Top candidate for "${intent}": score ${top.score}, selector ${top.selector}`
|
|
309
|
+
: `No candidates found for intent "${intent}"`,
|
|
310
|
+
status: payload.candidateCount > 0 ? 'success' : 'partial',
|
|
311
|
+
details: { intentScore: payload },
|
|
312
|
+
metadata: { executionTimeMs: Date.now() - startedAt },
|
|
313
|
+
})
|
|
314
|
+
);
|
|
315
|
+
} catch (err) {
|
|
316
|
+
rethrowIfUnavailable(err); // F1
|
|
317
|
+
return fail('intent-score', err.message);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (require.main === module) {
|
|
322
|
+
process.exit(runOrSkip('intent-score', main));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = { VALID_INTENTS, buildScript };
|