agentic-qe 3.9.8 → 3.9.10
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/agents/_shared/executor-preamble.md +86 -0
- package/.claude/agents/v3/qe-coverage-specialist.md +20 -1
- package/.claude/agents/v3/qe-fleet-commander.md +20 -1
- package/.claude/agents/v3/qe-pentest-validator.md +20 -1
- package/.claude/agents/v3/qe-queen-coordinator.md +20 -1
- package/.claude/agents/v3/qe-risk-assessor.md +20 -1
- package/.claude/agents/v3/qe-root-cause-analyzer.md +19 -0
- package/.claude/agents/v3/qe-security-auditor.md +20 -1
- package/.claude/agents/v3/qe-test-architect.md +33 -1
- package/.claude/helpers/advisor-call.cjs +283 -0
- 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 +75 -0
- package/README.md +5 -3
- package/assets/agents/v3/helpers/advisor-call.cjs +283 -0
- package/assets/agents/v3/qe-coverage-specialist.md +20 -1
- package/assets/agents/v3/qe-fleet-commander.md +20 -1
- package/assets/agents/v3/qe-pentest-validator.md +20 -1
- package/assets/agents/v3/qe-queen-coordinator.md +20 -1
- package/assets/agents/v3/qe-risk-assessor.md +20 -1
- package/assets/agents/v3/qe-root-cause-analyzer.md +19 -0
- package/assets/agents/v3/qe-security-auditor.md +20 -1
- package/assets/agents/v3/qe-test-architect.md +33 -1
- 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-IKCDCMSI.js +2 -0
- package/dist/cli/chunks/{agent-booster-wasm-LAE4NTVX.js → agent-booster-wasm-HM4XSABF.js} +2 -2
- package/dist/cli/chunks/{agent-handler-FVXHR6XN.js → agent-handler-UDBDLLO4.js} +2 -2
- package/dist/cli/chunks/{agent-memory-branch-Q7LLBA7C.js → agent-memory-branch-VIXQ3DAR.js} +2 -2
- package/dist/cli/chunks/aqe-learning-engine-W4WW7SQW.js +2 -0
- package/dist/cli/chunks/{audit-YRLKHJLX.js → audit-FWTGLQHH.js} +2 -2
- package/dist/cli/chunks/base-UQKFTHOY.js +2 -0
- package/dist/cli/chunks/{better-sqlite3-XFGOGICB.js → better-sqlite3-TYI3CCWU.js} +2 -2
- package/dist/cli/chunks/{brain-handler-KIUSNVSS.js → brain-handler-45ZGBLSB.js} +3 -3
- package/dist/cli/chunks/{branch-enumerator-VKZ4L3FH.js → branch-enumerator-ZBXELCQA.js} +2 -2
- package/dist/cli/chunks/{browser-GZVIYFIB.js → browser-2KM5IKEX.js} +2 -2
- package/dist/cli/chunks/browser-workflow-NMOEM3HW.js +2 -0
- package/dist/cli/chunks/{chunk-7PHNHFZI.js → chunk-226DSROQ.js} +3 -3
- package/dist/cli/chunks/{chunk-MGX2BZWE.js → chunk-27B575K6.js} +2 -2
- package/dist/cli/chunks/{chunk-P7APAQD6.js → chunk-2IJFZW3N.js} +12 -12
- package/dist/cli/chunks/{chunk-TWDWDKOI.js → chunk-32OB4ZYQ.js} +1 -1
- package/dist/cli/chunks/{chunk-E4D36LGH.js → chunk-335CCAOL.js} +1 -1
- package/dist/cli/chunks/{chunk-Q5PARJC6.js → chunk-34WI4QNF.js} +2 -2
- package/dist/cli/chunks/chunk-3A4BL62O.js +2 -0
- package/dist/cli/chunks/{chunk-6ZMM7MXA.js → chunk-3AG647MY.js} +2 -2
- package/dist/cli/chunks/{chunk-LPRHYSXN.js → chunk-3HIDCXW3.js} +1 -1
- package/dist/cli/chunks/{chunk-HN7HYUW6.js → chunk-4EKWEDHA.js} +9 -9
- package/dist/cli/chunks/{chunk-JCROLOP6.js → chunk-4FU6YNDP.js} +2 -2
- package/dist/cli/chunks/{chunk-A4DJMFDM.js → chunk-4LOJJ4VX.js} +1 -1
- package/dist/cli/chunks/{chunk-I25KIHQE.js → chunk-4VOGUZW5.js} +1 -1
- package/dist/cli/chunks/{chunk-KJZU3E5G.js → chunk-4ZR5G4MZ.js} +2 -2
- package/dist/cli/chunks/{chunk-W45FANJG.js → chunk-52ZHPZVX.js} +2 -2
- package/dist/cli/chunks/{chunk-LOANEFGZ.js → chunk-53G3OCGS.js} +2 -2
- package/dist/cli/chunks/{chunk-TZMKO6PC.js → chunk-54TZA65H.js} +2 -2
- package/dist/cli/chunks/{chunk-GHJRX7PV.js → chunk-5QKTLOGO.js} +1 -1
- package/dist/cli/chunks/{chunk-76UL224Z.js → chunk-5TATJQ3Z.js} +2 -2
- package/dist/cli/chunks/{chunk-OGFGNAKQ.js → chunk-5V6DRRLO.js} +2 -2
- package/dist/cli/chunks/{chunk-BXMIQRF3.js → chunk-6X7WKNDF.js} +2 -2
- package/dist/cli/chunks/chunk-7FWZHYYE.js +2 -0
- package/dist/cli/chunks/{chunk-R2LWLZ3Y.js → chunk-A2ULGMMG.js} +1 -1
- package/dist/cli/chunks/{chunk-AVKDT3UL.js → chunk-A53XKLEA.js} +8 -8
- package/dist/cli/chunks/{chunk-GOPE5OB5.js → chunk-A5OIXFFL.js} +1 -1
- package/dist/cli/chunks/{chunk-I7OH6RAC.js → chunk-ACNL4NFI.js} +2 -2
- package/dist/cli/chunks/{chunk-PBPOSPTY.js → chunk-AE6Y5CNJ.js} +2 -2
- package/dist/cli/chunks/{chunk-TN72MXLI.js → chunk-AO4HDN62.js} +2 -2
- package/dist/cli/chunks/{chunk-IHJXFWUL.js → chunk-AOA454FC.js} +2 -2
- package/dist/cli/chunks/{chunk-N2L7RWNX.js → chunk-B2QVWL5R.js} +2 -2
- package/dist/cli/chunks/{chunk-7CFEGUEH.js → chunk-B3L3CT4X.js} +2 -2
- package/dist/cli/chunks/{chunk-XVXSQOQG.js → chunk-B4AFVIOA.js} +2 -2
- package/dist/cli/chunks/{chunk-S72TSJS4.js → chunk-BCSCJBYQ.js} +2 -2
- package/dist/cli/chunks/{chunk-UAI5NPPQ.js → chunk-BIV6HWMT.js} +2 -2
- package/dist/cli/chunks/{chunk-XPL3BXLM.js → chunk-BNNH3KZP.js} +1 -1
- package/dist/cli/chunks/{chunk-JK6JBNGL.js → chunk-C234RGWZ.js} +2 -2
- package/dist/cli/chunks/{chunk-4EAAHMVM.js → chunk-C55GEYDA.js} +2 -2
- package/dist/cli/chunks/{chunk-Y67OXEUM.js → chunk-CEBZHZ4O.js} +1 -1
- package/dist/cli/chunks/{chunk-A2QLTNN5.js → chunk-CFQHIWWH.js} +1 -1
- package/dist/cli/chunks/{chunk-KMGAJRQ6.js → chunk-CJO2V2FB.js} +1 -1
- package/dist/cli/chunks/{chunk-5TGK7VTS.js → chunk-CQNXIYQW.js} +2 -2
- package/dist/cli/chunks/{chunk-IP2Z4Z6X.js → chunk-D2A4TGZY.js} +1 -1
- package/dist/cli/chunks/{chunk-VVNR4R22.js → chunk-DG2OYKUQ.js} +2 -2
- package/dist/cli/chunks/{chunk-ELZ5SKEN.js → chunk-DPYCHODC.js} +2 -2
- package/dist/cli/chunks/{chunk-WUCWFDBE.js → chunk-E4YKNKQL.js} +2 -2
- package/dist/cli/chunks/{chunk-ZCKNGICX.js → chunk-EEWTTYRC.js} +1 -1
- package/dist/cli/chunks/{chunk-IFIYNCT2.js → chunk-EGIYLRW5.js} +2 -2
- package/dist/cli/chunks/{chunk-DLKRK2GU.js → chunk-EHGTNSJ2.js} +1 -1
- package/dist/cli/chunks/{chunk-IIYXSWJN.js → chunk-EJNASXOY.js} +2 -2
- package/dist/cli/chunks/{chunk-ZJ4PMOIZ.js → chunk-F7HRGQRS.js} +2 -2
- package/dist/cli/chunks/{chunk-2QI5RYVR.js → chunk-FF7TSDO4.js} +2 -2
- package/dist/cli/chunks/{chunk-DDDEGBBJ.js → chunk-FIQNVPYY.js} +2 -2
- package/dist/cli/chunks/{chunk-F5VLJFVU.js → chunk-FJOBKT7N.js} +1 -1
- package/dist/cli/chunks/{chunk-JNJYWWBG.js → chunk-FYI52MFF.js} +6 -6
- package/dist/cli/chunks/{chunk-UOSKMAAY.js → chunk-GCNTU3QJ.js} +1 -1
- package/dist/cli/chunks/{chunk-4GMV6Z7Y.js → chunk-H56YBNXW.js} +2 -2
- package/dist/cli/chunks/{chunk-HTL2WT64.js → chunk-HJMLJNCB.js} +1 -1
- package/dist/cli/chunks/chunk-I3IRIJOT.js +2 -0
- package/dist/cli/chunks/chunk-IEQ2VYMO.js +3 -0
- package/dist/cli/chunks/{chunk-PG7CZ6Q4.js → chunk-IGRKFVFD.js} +2 -2
- package/dist/cli/chunks/{chunk-SQ6XZGR4.js → chunk-IJPE6OGD.js} +10 -10
- package/dist/cli/chunks/{chunk-AYKMWP7F.js → chunk-IJUL2UMO.js} +1 -1
- package/dist/cli/chunks/{chunk-JVH7753D.js → chunk-ISZJAZ2D.js} +1 -1
- package/dist/cli/chunks/{chunk-NCXVOOA7.js → chunk-ITDYTODU.js} +2 -2
- package/dist/cli/chunks/{chunk-RGCCSAHI.js → chunk-JHUEBBSX.js} +2 -2
- package/dist/cli/chunks/{chunk-TDPHLQ2M.js → chunk-JN3CC2TX.js} +2 -2
- package/dist/cli/chunks/{chunk-TSDTRJOG.js → chunk-JOEEGNNX.js} +2 -2
- package/dist/cli/chunks/{chunk-QVGSD25D.js → chunk-JQX2DHQT.js} +1 -1
- package/dist/cli/chunks/{chunk-VHZ653XS.js → chunk-JRG4AFUR.js} +3 -3
- package/dist/cli/chunks/{chunk-SP3ZBJ63.js → chunk-JRMNQWRL.js} +3 -3
- package/dist/cli/chunks/{chunk-EKDFIYV5.js → chunk-JXDJMVIG.js} +2 -2
- package/dist/cli/chunks/{chunk-3WOQMFTD.js → chunk-JYPW22JV.js} +2 -2
- package/dist/cli/chunks/{chunk-WJDOOT2M.js → chunk-KK3KVYE7.js} +2 -2
- package/dist/cli/chunks/{chunk-4KX6TMKB.js → chunk-KSRAA6ZD.js} +3 -3
- package/dist/cli/chunks/chunk-KUCU5ML6.js +6 -0
- package/dist/cli/chunks/{chunk-MVW7AACO.js → chunk-KXXLMLMJ.js} +2 -2
- package/dist/cli/chunks/{chunk-HE2NWYHK.js → chunk-LKCFJC4Q.js} +1 -1
- package/dist/cli/chunks/{chunk-237NNDKL.js → chunk-LODXDV4G.js} +2 -2
- package/dist/cli/chunks/{chunk-W4IRWGGR.js → chunk-M4CYXAVP.js} +4 -4
- package/dist/cli/chunks/{chunk-R4VOIXJQ.js → chunk-MOLMS6MA.js} +2 -2
- package/dist/cli/chunks/{chunk-SDMGF3KD.js → chunk-NBTM2J4B.js} +2 -2
- package/dist/cli/chunks/{chunk-X66IXWSO.js → chunk-NIFVFUCU.js} +2 -2
- package/dist/cli/chunks/{chunk-266SKKFM.js → chunk-OOHKW3UE.js} +2 -2
- package/dist/cli/chunks/{chunk-WXEDVKJS.js → chunk-ORA6NIXN.js} +2 -2
- package/dist/cli/chunks/{chunk-ECYDMBDA.js → chunk-OSD55UO7.js} +2 -2
- package/dist/cli/chunks/{chunk-SSURIMCL.js → chunk-OWQRMH3G.js} +2 -2
- package/dist/cli/chunks/chunk-QFUINEBN.js +2 -0
- package/dist/cli/chunks/{chunk-HYACMUUR.js → chunk-RE2IBX7Z.js} +2 -2
- package/dist/cli/chunks/{chunk-2V5VKOJ2.js → chunk-RMQQ5UHM.js} +2 -2
- package/dist/cli/chunks/{chunk-U62WL3WZ.js → chunk-ROEMVTXC.js} +3 -3
- package/dist/cli/chunks/{chunk-YOKRSFGA.js → chunk-SMTAZQJ3.js} +2 -2
- package/dist/cli/chunks/{chunk-OZTSMI7P.js → chunk-TO4NGP3E.js} +1 -1
- package/dist/cli/chunks/{chunk-LFEBTWFS.js → chunk-TTXYZUTQ.js} +2 -2
- package/dist/cli/chunks/{chunk-IZTUAI5T.js → chunk-U4NODKRR.js} +2 -2
- package/dist/cli/chunks/{chunk-JD3GH47Z.js → chunk-U635PSAW.js} +2 -2
- package/dist/cli/chunks/{chunk-6DBYVKGA.js → chunk-UBT7VCKQ.js} +2 -2
- package/dist/cli/chunks/{chunk-YSUMQBMY.js → chunk-UETM5XDO.js} +1 -1
- package/dist/cli/chunks/{chunk-BZB5D4BO.js → chunk-URXG7FMO.js} +4 -3
- package/dist/cli/chunks/{chunk-M2JBQVBP.js → chunk-VIWDVS24.js} +2 -2
- package/dist/cli/chunks/{chunk-6A4FEIE2.js → chunk-VNKCUKUJ.js} +3 -3
- package/dist/cli/chunks/{chunk-6KWX7A3R.js → chunk-VXIXHZCN.js} +2 -2
- package/dist/cli/chunks/{chunk-YIJDCZVX.js → chunk-WFEXEDMC.js} +2 -2
- package/dist/cli/chunks/{chunk-CG3HIYF4.js → chunk-WLX57ULC.js} +2 -2
- package/dist/cli/chunks/{chunk-FKODRXOU.js → chunk-WVQZGLCT.js} +2 -2
- package/dist/cli/chunks/{chunk-677V67MR.js → chunk-WW5DZ6BU.js} +1 -1
- package/dist/cli/chunks/{chunk-7L64UC5U.js → chunk-X364AIY6.js} +1 -1
- package/dist/cli/chunks/{chunk-UGJNR52C.js → chunk-XH7D6EGE.js} +1 -1
- package/dist/cli/chunks/{chunk-66DCG6RO.js → chunk-XICRAXUR.js} +4 -4
- package/dist/cli/chunks/{chunk-ETXK25IY.js → chunk-XMAV7AIC.js} +1 -1
- package/dist/cli/chunks/{chunk-NHXFAXEV.js → chunk-XSUPK7FI.js} +1 -1
- package/dist/cli/chunks/{chunk-3ZAGYTEC.js → chunk-XSWOB74I.js} +2 -2
- package/dist/cli/chunks/chunk-YPIZMTTA.js +14 -0
- package/dist/cli/chunks/{chunk-YDW522M7.js → chunk-YT6KBEXE.js} +2 -2
- package/dist/cli/chunks/{chunk-P2H5ARHM.js → chunk-ZENLP5LF.js} +1 -1
- package/dist/cli/chunks/{ci-A5ZXOEC4.js → ci-WS32HBBS.js} +2 -2
- package/dist/cli/chunks/{ci-output-S47BMRYC.js → ci-output-67R5MSLL.js} +2 -2
- package/dist/cli/chunks/circuit-breaker-MA562FT7.js +2 -0
- package/dist/cli/chunks/{claude-flow-setup-F5WBEBVK.js → claude-flow-setup-4QKGSRS7.js} +2 -2
- package/dist/cli/chunks/client-XQGZKXOB.js +2 -0
- package/dist/cli/chunks/{cline-installer-HLKR4QDR.js → cline-installer-6VSROHRY.js} +2 -2
- package/dist/cli/chunks/{code-MTZWS6JT.js → code-FBPBHVV3.js} +2 -2
- package/dist/cli/chunks/{code-index-extractor-BALTZ2WQ.js → code-index-extractor-62F622V2.js} +2 -2
- package/dist/cli/chunks/{codex-installer-LI2VIGET.js → codex-installer-LSR6DVCU.js} +2 -2
- package/dist/cli/chunks/{completions-TOF4GTNF.js → completions-56QOICBN.js} +2 -2
- package/dist/cli/chunks/{complexity-analyzer-IPFXIT6T.js → complexity-analyzer-SDH4NWIS.js} +2 -2
- package/dist/cli/chunks/{continuedev-installer-KWI66RBI.js → continuedev-installer-S7ZPL3VC.js} +2 -2
- package/dist/cli/chunks/{copilot-installer-REFOE6UF.js → copilot-installer-25GNNKNL.js} +2 -2
- package/dist/cli/chunks/{cost-tracker-M2MZQXCN.js → cost-tracker-73J4Y2RS.js} +2 -2
- package/dist/cli/chunks/{coverage-UR2XSJCR.js → coverage-WEE2AZ5F.js} +3 -3
- package/dist/cli/chunks/cross-domain-router-C2ZFCSXJ.js +2 -0
- package/dist/cli/chunks/{cursor-installer-X4PXCVYH.js → cursor-installer-DHQ644T3.js} +2 -2
- package/dist/cli/chunks/{daemon-5R6ZEEBB.js → daemon-3WUJ5E3X.js} +3 -3
- package/dist/cli/chunks/{dag-attention-scheduler-RUY2RJZA.js → dag-attention-scheduler-IRLAM43H.js} +2 -2
- package/dist/cli/chunks/{detect-PX2AYBHM.js → detect-DTSB4T4R.js} +2 -2
- package/dist/cli/chunks/{domain-handler-5JXWEO3E.js → domain-handler-DDN2Z5XC.js} +2 -2
- package/dist/cli/chunks/{domain-transfer-6M2YLBJY.js → domain-transfer-3RRG4S6R.js} +2 -2
- package/dist/cli/chunks/dream-JSZZ67OO.js +2 -0
- package/dist/cli/chunks/esm-node-X4TES6NX.js +2 -0
- package/dist/cli/chunks/{eval-L6ZBG462.js → eval-UXEP425X.js} +2 -2
- package/dist/cli/chunks/{fast-paths-WIFDALFK.js → fast-paths-4XLHS2VN.js} +2 -2
- package/dist/cli/chunks/{feature-flags-YLBXFUCN.js → feature-flags-6C2HD76K.js} +2 -2
- package/dist/cli/chunks/{feature-flags-GRHF5MTK.js → feature-flags-KXXHAEYF.js} +2 -2
- package/dist/cli/chunks/{file-discovery-4HXUB4HN.js → file-discovery-YSDUIZO4.js} +2 -2
- package/dist/cli/chunks/{fleet-RPLJXOEP.js → fleet-TYDG5DWK.js} +3 -3
- package/dist/cli/chunks/{gnn-wrapper-2D5IOGAT.js → gnn-wrapper-GJVYRPHB.js} +2 -2
- package/dist/cli/chunks/{heartbeat-handler-D5SWZZGA.js → heartbeat-handler-X63CM35O.js} +4 -4
- package/dist/cli/chunks/{heartbeat-scheduler-WSG4Y3M2.js → heartbeat-scheduler-NYH4CMVM.js} +2 -2
- package/dist/cli/chunks/hnsw-adapter-SQCVEHB5.js +2 -0
- package/dist/cli/chunks/hnsw-index-UGVC5IDK.js +2 -0
- package/dist/cli/chunks/{hnsw-legacy-bridge-UH6RWE74.js → hnsw-legacy-bridge-YDVUZTJI.js} +2 -2
- package/dist/cli/chunks/{hnswlib-node-BJ4ZJPMP.js → hnswlib-node-TLBDFWA6.js} +2 -2
- package/dist/cli/chunks/{hooks-KGDQNB5T.js → hooks-B6PVGP7D.js} +6 -6
- package/dist/cli/chunks/hybrid-router-YZEBKUZJ.js +2 -0
- package/dist/cli/chunks/{hypergraph-engine-LARQCK7V.js → hypergraph-engine-OQ2ZEG53.js} +2 -2
- package/dist/cli/chunks/{hypergraph-handler-RACF4AOX.js → hypergraph-handler-VPD424MI.js} +3 -3
- package/dist/cli/chunks/impact-analyzer-ZIXSRWED.js +2 -0
- package/dist/cli/chunks/{init-handler-64AOFMJD.js → init-handler-5WYP6NJW.js} +6 -6
- package/dist/cli/chunks/init-wizard-MO6PCXPX.js +2 -0
- package/dist/cli/chunks/kernel-P54KQB2F.js +2 -0
- package/dist/cli/chunks/{kilocode-installer-4ICIP6QN.js → kilocode-installer-YVY4EVMY.js} +2 -2
- package/dist/cli/chunks/{kiro-installer-J2GOV2OB.js → kiro-installer-GNT4BN3A.js} +2 -2
- package/dist/cli/chunks/knowledge-graph-GU57FQAQ.js +2 -0
- package/dist/cli/chunks/{learning-QD4JVH3K.js → learning-LD2RSBRS.js} +3 -3
- package/dist/cli/chunks/llm-router-ALKXFKLQ.js +36 -0
- package/dist/cli/chunks/{load-EXKUJMBK.js → load-XAOTGZYB.js} +2 -2
- package/dist/cli/chunks/load-test-5RFBTSS7.js +2 -0
- package/dist/cli/chunks/{mcp-NSNDZSMH.js → mcp-WDAJHGH4.js} +2 -2
- package/dist/cli/chunks/{memory-63JTNVZN.js → memory-M7QD57JD.js} +5 -5
- package/dist/cli/chunks/memory-backend-GPOP3IR4.js +2 -0
- package/dist/cli/chunks/memory-handlers-2NHGZLQM.js +2 -0
- package/dist/cli/chunks/multi-model-executor-2XZQK2IN.js +14 -0
- package/dist/cli/chunks/{opencode-installer-244LFSPN.js → opencode-installer-ASCVY3GG.js} +2 -2
- package/dist/cli/chunks/{orchestrator-TZB457J6.js → orchestrator-GOZICWN3.js} +22 -19
- package/dist/cli/chunks/{pipeline-YLBD2Z5Q.js → pipeline-YHQRJWV3.js} +2 -2
- package/dist/cli/chunks/{platform-53PWFZSE.js → platform-4NESYFHN.js} +2 -2
- package/dist/cli/chunks/{plugin-6GUQEFJU.js → plugin-E24I2RVB.js} +2 -2
- package/dist/cli/chunks/{prime-radiant-advanced-wasm-VCOK7FV5.js → prime-radiant-advanced-wasm-CDVSLR7R.js} +2 -2
- package/dist/cli/chunks/protocol-executor-M5IONISJ.js +2 -0
- package/dist/cli/chunks/{protocol-handler-25UEGTE2.js → protocol-handler-TGTDKSZB.js} +2 -2
- package/dist/cli/chunks/{prove-CTOU5F6G.js → prove-WUKDAMSE.js} +2 -2
- package/dist/cli/chunks/provider-manager-BTKK6W7M.js +24 -0
- package/dist/cli/chunks/qe-reasoning-bank-WIEXCBVE.js +2 -0
- package/dist/cli/chunks/{quality-PB7H5UEF.js → quality-RTIOIS2K.js} +2 -2
- package/dist/cli/chunks/queen-coordinator-ZFK6DANW.js +2 -0
- package/dist/cli/chunks/{real-embeddings-RWWYCIE5.js → real-embeddings-4JJKAEMO.js} +2 -2
- package/dist/cli/chunks/{roocode-installer-U4AGYVKL.js → roocode-installer-XU2IXRBM.js} +2 -2
- package/dist/cli/chunks/router-TOFBEI2Q.js +2 -0
- package/dist/cli/chunks/routing-feedback-RC2VDP6W.js +2 -0
- package/dist/cli/chunks/{routing-handler-NTDKDEBE.js → routing-handler-3KBOCIEN.js} +2 -2
- package/dist/cli/chunks/{ruvector-commands-RQKOLQSW.js → ruvector-commands-HHE2ZPX7.js} +2 -2
- package/dist/cli/chunks/{rvf-dual-writer-6EZ7S7OG.js → rvf-dual-writer-GAWM2BUZ.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-adapter-EBTV6FV2.js → rvf-migration-adapter-HQPEC4BN.js} +2 -2
- package/dist/cli/chunks/{rvf-migration-coordinator-MERU7VLY.js → rvf-migration-coordinator-A4K45EFU.js} +2 -2
- package/dist/cli/chunks/rvf-native-adapter-ZOQDH3JY.js +2 -0
- package/dist/cli/chunks/safe-db-RIP3X32S.js +2 -0
- package/dist/cli/chunks/schedule-Q6KZRLWS.js +2 -0
- package/dist/cli/chunks/scheduler-SJO5QPAU.js +2 -0
- package/dist/cli/chunks/{security-JPDLGHMC.js → security-UIKUNOXB.js} +3 -3
- package/dist/cli/chunks/shared-rvf-adapter-JJCR3AWU.js +2 -0
- package/dist/cli/chunks/{shared-rvf-dual-writer-7OGLQE5Y.js → shared-rvf-dual-writer-ZUWSLFPH.js} +2 -2
- package/dist/cli/chunks/sqlite-persistence-HK2S6XAI.js +2 -0
- package/dist/cli/chunks/{status-handler-3TI3DHEL.js → status-handler-E3VSWGA6.js} +2 -2
- package/dist/cli/chunks/{structural-health-WCZKXVWS.js → structural-health-Y22H4BOU.js} +2 -2
- package/dist/cli/chunks/{sync-AM5T4GYO.js → sync-CA4KWZFS.js} +2 -2
- package/dist/cli/chunks/{task-handler-VHDTXPVP.js → task-handler-3EZPIAMD.js} +2 -2
- package/dist/cli/chunks/task-handlers-6UVAQAGP.js +2 -0
- package/dist/cli/chunks/{test-G6P5XGHM.js → test-Q5DOFSJI.js} +4 -4
- package/dist/cli/chunks/{test-scheduling-37RBUN4E.js → test-scheduling-BSXWCIMQ.js} +3 -3
- package/dist/cli/chunks/token-bootstrap-XGEZU2CS.js +2 -0
- package/dist/cli/chunks/{token-usage-5XGVBLFR.js → token-usage-BZX5TCG6.js} +2 -2
- package/dist/cli/chunks/{transformers-JTKWAZJU.js → transformers-7ITQPXAU.js} +2 -2
- package/dist/cli/chunks/{tree-sitter-wasm-parser-KW2GWIIQ.js → tree-sitter-wasm-parser-ZYBBNYR3.js} +2 -2
- package/dist/cli/chunks/{types-7R72BACI.js → types-ACZ5VVRC.js} +2 -2
- package/dist/cli/chunks/unified-memory-EXO6WK33.js +2 -0
- package/dist/cli/chunks/unified-memory-hnsw-7HPSTFVV.js +2 -0
- package/dist/cli/chunks/unified-persistence-WC3O4WOJ.js +2 -0
- package/dist/cli/chunks/{validate-TYB4ZTUL.js → validate-IQL6OVXD.js} +2 -2
- package/dist/cli/chunks/{validate-swarm-3TFI6PLT.js → validate-swarm-J52J2K5X.js} +2 -2
- package/dist/cli/chunks/{vibium-3YELURJT.js → vibium-XSE76PXE.js} +2 -2
- package/dist/cli/chunks/visual-security-COW3OCEE.js +2 -0
- package/dist/cli/chunks/{web-tree-sitter-7Q77A27Y.js → web-tree-sitter-YM6QXUIY.js} +2 -2
- package/dist/cli/chunks/{windsurf-installer-ASARRM2X.js → windsurf-installer-M27DVL4H.js} +2 -2
- package/dist/cli/chunks/{witness-chain-WZ6PNXEY.js → witness-chain-NB5LP73S.js} +2 -2
- package/dist/cli/chunks/witness-chain-XQXF3RSP.js +2 -0
- package/dist/cli/chunks/{workflow-JDTEE6TY.js → workflow-5DODQ6XS.js} +4 -4
- package/dist/cli/chunks/workflow-orchestrator-HSIZEKZM.js +2 -0
- package/dist/cli/chunks/{wrappers-X7WZLBZD.js → wrappers-K7HHCIYD.js} +2 -2
- package/dist/cli/commands/llm-router.js +252 -0
- package/dist/coordination/queen-task-management.js +8 -1
- package/dist/init/browser-engine-installer.d.ts +60 -0
- package/dist/init/browser-engine-installer.js +92 -0
- package/dist/init/init-wizard-steps.js +9 -0
- package/dist/init/phases/09-assets.d.ts +2 -0
- package/dist/init/phases/09-assets.js +65 -0
- package/dist/init/phases/12-verification.js +8 -0
- package/dist/init/skills-installer.js +1 -0
- package/dist/kernel/unified-memory-schemas.d.ts +1 -1
- package/dist/kernel/unified-memory-schemas.js +2 -1
- package/dist/mcp/bundle.js +47 -44
- package/dist/mcp/protocol-server.js +87 -0
- package/dist/routing/advisor/circuit-breaker.d.ts +56 -0
- package/dist/routing/advisor/circuit-breaker.js +128 -0
- package/dist/routing/advisor/domain-prompts.d.ts +14 -0
- package/dist/routing/advisor/domain-prompts.js +53 -0
- package/dist/routing/advisor/index.d.ts +10 -0
- package/dist/routing/advisor/index.js +9 -0
- package/dist/routing/advisor/multi-model-executor.d.ts +60 -0
- package/dist/routing/advisor/multi-model-executor.js +176 -0
- package/dist/routing/advisor/redaction.d.ts +40 -0
- package/dist/routing/advisor/redaction.js +187 -0
- package/dist/routing/advisor/types.d.ts +101 -0
- package/dist/routing/advisor/types.js +9 -0
- package/dist/routing/queen-integration.d.ts +3 -0
- package/dist/routing/queen-integration.js +7 -1
- package/dist/routing/routing-feedback.d.ts +7 -1
- package/dist/routing/routing-feedback.js +57 -11
- package/dist/routing/tiny-dancer-router.d.ts +35 -1
- package/dist/routing/tiny-dancer-router.js +33 -0
- package/dist/routing/types.d.ts +12 -0
- package/package.json +1 -1
- package/dist/cli/chunks/adapter-D4XQUIJD.js +0 -2
- package/dist/cli/chunks/aqe-learning-engine-CGIWYLIP.js +0 -2
- package/dist/cli/chunks/base-BYVP2STR.js +0 -2
- package/dist/cli/chunks/browser-workflow-PC4N5TKL.js +0 -2
- package/dist/cli/chunks/chunk-2K3DJ3EK.js +0 -7
- package/dist/cli/chunks/chunk-JBQ4WGB4.js +0 -14
- package/dist/cli/chunks/chunk-OT4JADWW.js +0 -2
- package/dist/cli/chunks/client-56BU3GAX.js +0 -2
- package/dist/cli/chunks/cross-domain-router-XQT52BTB.js +0 -2
- package/dist/cli/chunks/dream-LFZCN5WK.js +0 -2
- package/dist/cli/chunks/esm-node-EBDIEPKS.js +0 -2
- package/dist/cli/chunks/hnsw-adapter-BMXTVGZB.js +0 -2
- package/dist/cli/chunks/hnsw-index-YX6XLICT.js +0 -2
- package/dist/cli/chunks/impact-analyzer-MGSI2WBK.js +0 -2
- package/dist/cli/chunks/init-wizard-TBDWRRMC.js +0 -2
- package/dist/cli/chunks/kernel-NV7TO2FK.js +0 -2
- package/dist/cli/chunks/knowledge-graph-7REGYH6A.js +0 -2
- package/dist/cli/chunks/llm-router-4K4IT2PQ.js +0 -30
- package/dist/cli/chunks/load-test-RYQK44TT.js +0 -2
- package/dist/cli/chunks/memory-backend-3EBE2DEX.js +0 -2
- package/dist/cli/chunks/memory-handlers-2335MVQJ.js +0 -2
- package/dist/cli/chunks/protocol-executor-MR37S7GX.js +0 -2
- package/dist/cli/chunks/qe-reasoning-bank-DANGLPTH.js +0 -2
- package/dist/cli/chunks/queen-coordinator-4YJPYF5F.js +0 -2
- package/dist/cli/chunks/router-F4IPY4RQ.js +0 -2
- package/dist/cli/chunks/routing-feedback-VGHFIJ5S.js +0 -2
- package/dist/cli/chunks/rvf-native-adapter-2P75WF5A.js +0 -2
- package/dist/cli/chunks/safe-db-47NEO2RS.js +0 -2
- package/dist/cli/chunks/schedule-L5GJW25Z.js +0 -2
- package/dist/cli/chunks/scheduler-NGGGSZMO.js +0 -2
- package/dist/cli/chunks/shared-rvf-adapter-NKNTYGHO.js +0 -2
- package/dist/cli/chunks/sqlite-persistence-TE2ZRHKA.js +0 -2
- package/dist/cli/chunks/task-handlers-GEJ36WNB.js +0 -2
- package/dist/cli/chunks/token-bootstrap-JPE3LWXQ.js +0 -2
- package/dist/cli/chunks/unified-memory-KSBLUZT4.js +0 -2
- package/dist/cli/chunks/unified-memory-hnsw-V3EOMQIZ.js +0 -2
- package/dist/cli/chunks/unified-persistence-URIRJ4BM.js +0 -2
- package/dist/cli/chunks/visual-security-DJOOVCBZ.js +0 -2
- package/dist/cli/chunks/witness-chain-ZWJUCXCJ.js +0 -2
- package/dist/cli/chunks/workflow-orchestrator-5CKA6Q74.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 };
|