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.
Files changed (394) hide show
  1. package/.claude/agents/_shared/executor-preamble.md +86 -0
  2. package/.claude/agents/v3/qe-coverage-specialist.md +20 -1
  3. package/.claude/agents/v3/qe-fleet-commander.md +20 -1
  4. package/.claude/agents/v3/qe-pentest-validator.md +20 -1
  5. package/.claude/agents/v3/qe-queen-coordinator.md +20 -1
  6. package/.claude/agents/v3/qe-risk-assessor.md +20 -1
  7. package/.claude/agents/v3/qe-root-cause-analyzer.md +19 -0
  8. package/.claude/agents/v3/qe-security-auditor.md +20 -1
  9. package/.claude/agents/v3/qe-test-architect.md +33 -1
  10. package/.claude/helpers/advisor-call.cjs +283 -0
  11. package/.claude/skills/README.md +4 -3
  12. package/.claude/skills/a11y-ally/SKILL.md +40 -18
  13. package/.claude/skills/accessibility-testing/SKILL.md +4 -0
  14. package/.claude/skills/compatibility-testing/SKILL.md +23 -0
  15. package/.claude/skills/e2e-flow-verifier/SKILL.md +87 -52
  16. package/.claude/skills/enterprise-integration-testing/SKILL.md +4 -0
  17. package/.claude/skills/localization-testing/SKILL.md +14 -0
  18. package/.claude/skills/observability-testing-patterns/SKILL.md +16 -0
  19. package/.claude/skills/qe-browser/SKILL.md +409 -0
  20. package/.claude/skills/qe-browser/evals/qe-browser.yaml +291 -0
  21. package/.claude/skills/qe-browser/fixtures/package.json +7 -0
  22. package/.claude/skills/qe-browser/fixtures/serve-skills.js +130 -0
  23. package/.claude/skills/qe-browser/references/assertion-kinds.md +132 -0
  24. package/.claude/skills/qe-browser/references/migration-from-playwright.md +195 -0
  25. package/.claude/skills/qe-browser/schemas/output.json +188 -0
  26. package/.claude/skills/qe-browser/scripts/assert.js +378 -0
  27. package/.claude/skills/qe-browser/scripts/batch.js +292 -0
  28. package/.claude/skills/qe-browser/scripts/check-injection.js +267 -0
  29. package/.claude/skills/qe-browser/scripts/intent-score.js +325 -0
  30. package/.claude/skills/qe-browser/scripts/lib/vibium.js +330 -0
  31. package/.claude/skills/qe-browser/scripts/package.json +7 -0
  32. package/.claude/skills/qe-browser/scripts/smoke-test.sh +212 -0
  33. package/.claude/skills/qe-browser/scripts/validate-config.json +46 -0
  34. package/.claude/skills/qe-browser/scripts/visual-diff.js +276 -0
  35. package/.claude/skills/qe-visual-accessibility/SKILL.md +31 -1
  36. package/.claude/skills/security-visual-testing/SKILL.md +18 -0
  37. package/.claude/skills/skills-manifest.json +20 -13
  38. package/.claude/skills/testability-scoring/SKILL.md +23 -0
  39. package/.claude/skills/trust-tier-manifest.json +14 -3
  40. package/.claude/skills/visual-testing-advanced/SKILL.md +41 -1
  41. package/CHANGELOG.md +75 -0
  42. package/README.md +5 -3
  43. package/assets/agents/v3/helpers/advisor-call.cjs +283 -0
  44. package/assets/agents/v3/qe-coverage-specialist.md +20 -1
  45. package/assets/agents/v3/qe-fleet-commander.md +20 -1
  46. package/assets/agents/v3/qe-pentest-validator.md +20 -1
  47. package/assets/agents/v3/qe-queen-coordinator.md +20 -1
  48. package/assets/agents/v3/qe-risk-assessor.md +20 -1
  49. package/assets/agents/v3/qe-root-cause-analyzer.md +19 -0
  50. package/assets/agents/v3/qe-security-auditor.md +20 -1
  51. package/assets/agents/v3/qe-test-architect.md +33 -1
  52. package/assets/skills/README.md +4 -3
  53. package/assets/skills/a11y-ally/SKILL.md +40 -18
  54. package/assets/skills/accessibility-testing/SKILL.md +4 -0
  55. package/assets/skills/compatibility-testing/SKILL.md +23 -0
  56. package/assets/skills/e2e-flow-verifier/SKILL.md +87 -52
  57. package/assets/skills/enterprise-integration-testing/SKILL.md +4 -0
  58. package/assets/skills/localization-testing/SKILL.md +14 -0
  59. package/assets/skills/observability-testing-patterns/SKILL.md +16 -0
  60. package/assets/skills/qe-browser/SKILL.md +409 -0
  61. package/assets/skills/qe-browser/evals/qe-browser.yaml +291 -0
  62. package/assets/skills/qe-browser/fixtures/package.json +7 -0
  63. package/assets/skills/qe-browser/fixtures/serve-skills.js +130 -0
  64. package/assets/skills/qe-browser/references/assertion-kinds.md +132 -0
  65. package/assets/skills/qe-browser/references/migration-from-playwright.md +195 -0
  66. package/assets/skills/qe-browser/schemas/output.json +188 -0
  67. package/assets/skills/qe-browser/scripts/assert.js +378 -0
  68. package/assets/skills/qe-browser/scripts/batch.js +292 -0
  69. package/assets/skills/qe-browser/scripts/check-injection.js +267 -0
  70. package/assets/skills/qe-browser/scripts/intent-score.js +325 -0
  71. package/assets/skills/qe-browser/scripts/lib/vibium.js +330 -0
  72. package/assets/skills/qe-browser/scripts/package.json +7 -0
  73. package/assets/skills/qe-browser/scripts/smoke-test.sh +212 -0
  74. package/assets/skills/qe-browser/scripts/validate-config.json +46 -0
  75. package/assets/skills/qe-browser/scripts/visual-diff.js +276 -0
  76. package/assets/skills/qe-visual-accessibility/SKILL.md +31 -1
  77. package/assets/skills/security-visual-testing/SKILL.md +18 -0
  78. package/assets/skills/skills-manifest.json +211 -15
  79. package/assets/skills/testability-scoring/SKILL.md +23 -0
  80. package/assets/skills/trust-tier-manifest.json +14 -3
  81. package/assets/skills/visual-testing-advanced/SKILL.md +41 -1
  82. package/dist/cli/bundle.js +5 -5
  83. package/dist/cli/chunks/adapter-IKCDCMSI.js +2 -0
  84. package/dist/cli/chunks/{agent-booster-wasm-LAE4NTVX.js → agent-booster-wasm-HM4XSABF.js} +2 -2
  85. package/dist/cli/chunks/{agent-handler-FVXHR6XN.js → agent-handler-UDBDLLO4.js} +2 -2
  86. package/dist/cli/chunks/{agent-memory-branch-Q7LLBA7C.js → agent-memory-branch-VIXQ3DAR.js} +2 -2
  87. package/dist/cli/chunks/aqe-learning-engine-W4WW7SQW.js +2 -0
  88. package/dist/cli/chunks/{audit-YRLKHJLX.js → audit-FWTGLQHH.js} +2 -2
  89. package/dist/cli/chunks/base-UQKFTHOY.js +2 -0
  90. package/dist/cli/chunks/{better-sqlite3-XFGOGICB.js → better-sqlite3-TYI3CCWU.js} +2 -2
  91. package/dist/cli/chunks/{brain-handler-KIUSNVSS.js → brain-handler-45ZGBLSB.js} +3 -3
  92. package/dist/cli/chunks/{branch-enumerator-VKZ4L3FH.js → branch-enumerator-ZBXELCQA.js} +2 -2
  93. package/dist/cli/chunks/{browser-GZVIYFIB.js → browser-2KM5IKEX.js} +2 -2
  94. package/dist/cli/chunks/browser-workflow-NMOEM3HW.js +2 -0
  95. package/dist/cli/chunks/{chunk-7PHNHFZI.js → chunk-226DSROQ.js} +3 -3
  96. package/dist/cli/chunks/{chunk-MGX2BZWE.js → chunk-27B575K6.js} +2 -2
  97. package/dist/cli/chunks/{chunk-P7APAQD6.js → chunk-2IJFZW3N.js} +12 -12
  98. package/dist/cli/chunks/{chunk-TWDWDKOI.js → chunk-32OB4ZYQ.js} +1 -1
  99. package/dist/cli/chunks/{chunk-E4D36LGH.js → chunk-335CCAOL.js} +1 -1
  100. package/dist/cli/chunks/{chunk-Q5PARJC6.js → chunk-34WI4QNF.js} +2 -2
  101. package/dist/cli/chunks/chunk-3A4BL62O.js +2 -0
  102. package/dist/cli/chunks/{chunk-6ZMM7MXA.js → chunk-3AG647MY.js} +2 -2
  103. package/dist/cli/chunks/{chunk-LPRHYSXN.js → chunk-3HIDCXW3.js} +1 -1
  104. package/dist/cli/chunks/{chunk-HN7HYUW6.js → chunk-4EKWEDHA.js} +9 -9
  105. package/dist/cli/chunks/{chunk-JCROLOP6.js → chunk-4FU6YNDP.js} +2 -2
  106. package/dist/cli/chunks/{chunk-A4DJMFDM.js → chunk-4LOJJ4VX.js} +1 -1
  107. package/dist/cli/chunks/{chunk-I25KIHQE.js → chunk-4VOGUZW5.js} +1 -1
  108. package/dist/cli/chunks/{chunk-KJZU3E5G.js → chunk-4ZR5G4MZ.js} +2 -2
  109. package/dist/cli/chunks/{chunk-W45FANJG.js → chunk-52ZHPZVX.js} +2 -2
  110. package/dist/cli/chunks/{chunk-LOANEFGZ.js → chunk-53G3OCGS.js} +2 -2
  111. package/dist/cli/chunks/{chunk-TZMKO6PC.js → chunk-54TZA65H.js} +2 -2
  112. package/dist/cli/chunks/{chunk-GHJRX7PV.js → chunk-5QKTLOGO.js} +1 -1
  113. package/dist/cli/chunks/{chunk-76UL224Z.js → chunk-5TATJQ3Z.js} +2 -2
  114. package/dist/cli/chunks/{chunk-OGFGNAKQ.js → chunk-5V6DRRLO.js} +2 -2
  115. package/dist/cli/chunks/{chunk-BXMIQRF3.js → chunk-6X7WKNDF.js} +2 -2
  116. package/dist/cli/chunks/chunk-7FWZHYYE.js +2 -0
  117. package/dist/cli/chunks/{chunk-R2LWLZ3Y.js → chunk-A2ULGMMG.js} +1 -1
  118. package/dist/cli/chunks/{chunk-AVKDT3UL.js → chunk-A53XKLEA.js} +8 -8
  119. package/dist/cli/chunks/{chunk-GOPE5OB5.js → chunk-A5OIXFFL.js} +1 -1
  120. package/dist/cli/chunks/{chunk-I7OH6RAC.js → chunk-ACNL4NFI.js} +2 -2
  121. package/dist/cli/chunks/{chunk-PBPOSPTY.js → chunk-AE6Y5CNJ.js} +2 -2
  122. package/dist/cli/chunks/{chunk-TN72MXLI.js → chunk-AO4HDN62.js} +2 -2
  123. package/dist/cli/chunks/{chunk-IHJXFWUL.js → chunk-AOA454FC.js} +2 -2
  124. package/dist/cli/chunks/{chunk-N2L7RWNX.js → chunk-B2QVWL5R.js} +2 -2
  125. package/dist/cli/chunks/{chunk-7CFEGUEH.js → chunk-B3L3CT4X.js} +2 -2
  126. package/dist/cli/chunks/{chunk-XVXSQOQG.js → chunk-B4AFVIOA.js} +2 -2
  127. package/dist/cli/chunks/{chunk-S72TSJS4.js → chunk-BCSCJBYQ.js} +2 -2
  128. package/dist/cli/chunks/{chunk-UAI5NPPQ.js → chunk-BIV6HWMT.js} +2 -2
  129. package/dist/cli/chunks/{chunk-XPL3BXLM.js → chunk-BNNH3KZP.js} +1 -1
  130. package/dist/cli/chunks/{chunk-JK6JBNGL.js → chunk-C234RGWZ.js} +2 -2
  131. package/dist/cli/chunks/{chunk-4EAAHMVM.js → chunk-C55GEYDA.js} +2 -2
  132. package/dist/cli/chunks/{chunk-Y67OXEUM.js → chunk-CEBZHZ4O.js} +1 -1
  133. package/dist/cli/chunks/{chunk-A2QLTNN5.js → chunk-CFQHIWWH.js} +1 -1
  134. package/dist/cli/chunks/{chunk-KMGAJRQ6.js → chunk-CJO2V2FB.js} +1 -1
  135. package/dist/cli/chunks/{chunk-5TGK7VTS.js → chunk-CQNXIYQW.js} +2 -2
  136. package/dist/cli/chunks/{chunk-IP2Z4Z6X.js → chunk-D2A4TGZY.js} +1 -1
  137. package/dist/cli/chunks/{chunk-VVNR4R22.js → chunk-DG2OYKUQ.js} +2 -2
  138. package/dist/cli/chunks/{chunk-ELZ5SKEN.js → chunk-DPYCHODC.js} +2 -2
  139. package/dist/cli/chunks/{chunk-WUCWFDBE.js → chunk-E4YKNKQL.js} +2 -2
  140. package/dist/cli/chunks/{chunk-ZCKNGICX.js → chunk-EEWTTYRC.js} +1 -1
  141. package/dist/cli/chunks/{chunk-IFIYNCT2.js → chunk-EGIYLRW5.js} +2 -2
  142. package/dist/cli/chunks/{chunk-DLKRK2GU.js → chunk-EHGTNSJ2.js} +1 -1
  143. package/dist/cli/chunks/{chunk-IIYXSWJN.js → chunk-EJNASXOY.js} +2 -2
  144. package/dist/cli/chunks/{chunk-ZJ4PMOIZ.js → chunk-F7HRGQRS.js} +2 -2
  145. package/dist/cli/chunks/{chunk-2QI5RYVR.js → chunk-FF7TSDO4.js} +2 -2
  146. package/dist/cli/chunks/{chunk-DDDEGBBJ.js → chunk-FIQNVPYY.js} +2 -2
  147. package/dist/cli/chunks/{chunk-F5VLJFVU.js → chunk-FJOBKT7N.js} +1 -1
  148. package/dist/cli/chunks/{chunk-JNJYWWBG.js → chunk-FYI52MFF.js} +6 -6
  149. package/dist/cli/chunks/{chunk-UOSKMAAY.js → chunk-GCNTU3QJ.js} +1 -1
  150. package/dist/cli/chunks/{chunk-4GMV6Z7Y.js → chunk-H56YBNXW.js} +2 -2
  151. package/dist/cli/chunks/{chunk-HTL2WT64.js → chunk-HJMLJNCB.js} +1 -1
  152. package/dist/cli/chunks/chunk-I3IRIJOT.js +2 -0
  153. package/dist/cli/chunks/chunk-IEQ2VYMO.js +3 -0
  154. package/dist/cli/chunks/{chunk-PG7CZ6Q4.js → chunk-IGRKFVFD.js} +2 -2
  155. package/dist/cli/chunks/{chunk-SQ6XZGR4.js → chunk-IJPE6OGD.js} +10 -10
  156. package/dist/cli/chunks/{chunk-AYKMWP7F.js → chunk-IJUL2UMO.js} +1 -1
  157. package/dist/cli/chunks/{chunk-JVH7753D.js → chunk-ISZJAZ2D.js} +1 -1
  158. package/dist/cli/chunks/{chunk-NCXVOOA7.js → chunk-ITDYTODU.js} +2 -2
  159. package/dist/cli/chunks/{chunk-RGCCSAHI.js → chunk-JHUEBBSX.js} +2 -2
  160. package/dist/cli/chunks/{chunk-TDPHLQ2M.js → chunk-JN3CC2TX.js} +2 -2
  161. package/dist/cli/chunks/{chunk-TSDTRJOG.js → chunk-JOEEGNNX.js} +2 -2
  162. package/dist/cli/chunks/{chunk-QVGSD25D.js → chunk-JQX2DHQT.js} +1 -1
  163. package/dist/cli/chunks/{chunk-VHZ653XS.js → chunk-JRG4AFUR.js} +3 -3
  164. package/dist/cli/chunks/{chunk-SP3ZBJ63.js → chunk-JRMNQWRL.js} +3 -3
  165. package/dist/cli/chunks/{chunk-EKDFIYV5.js → chunk-JXDJMVIG.js} +2 -2
  166. package/dist/cli/chunks/{chunk-3WOQMFTD.js → chunk-JYPW22JV.js} +2 -2
  167. package/dist/cli/chunks/{chunk-WJDOOT2M.js → chunk-KK3KVYE7.js} +2 -2
  168. package/dist/cli/chunks/{chunk-4KX6TMKB.js → chunk-KSRAA6ZD.js} +3 -3
  169. package/dist/cli/chunks/chunk-KUCU5ML6.js +6 -0
  170. package/dist/cli/chunks/{chunk-MVW7AACO.js → chunk-KXXLMLMJ.js} +2 -2
  171. package/dist/cli/chunks/{chunk-HE2NWYHK.js → chunk-LKCFJC4Q.js} +1 -1
  172. package/dist/cli/chunks/{chunk-237NNDKL.js → chunk-LODXDV4G.js} +2 -2
  173. package/dist/cli/chunks/{chunk-W4IRWGGR.js → chunk-M4CYXAVP.js} +4 -4
  174. package/dist/cli/chunks/{chunk-R4VOIXJQ.js → chunk-MOLMS6MA.js} +2 -2
  175. package/dist/cli/chunks/{chunk-SDMGF3KD.js → chunk-NBTM2J4B.js} +2 -2
  176. package/dist/cli/chunks/{chunk-X66IXWSO.js → chunk-NIFVFUCU.js} +2 -2
  177. package/dist/cli/chunks/{chunk-266SKKFM.js → chunk-OOHKW3UE.js} +2 -2
  178. package/dist/cli/chunks/{chunk-WXEDVKJS.js → chunk-ORA6NIXN.js} +2 -2
  179. package/dist/cli/chunks/{chunk-ECYDMBDA.js → chunk-OSD55UO7.js} +2 -2
  180. package/dist/cli/chunks/{chunk-SSURIMCL.js → chunk-OWQRMH3G.js} +2 -2
  181. package/dist/cli/chunks/chunk-QFUINEBN.js +2 -0
  182. package/dist/cli/chunks/{chunk-HYACMUUR.js → chunk-RE2IBX7Z.js} +2 -2
  183. package/dist/cli/chunks/{chunk-2V5VKOJ2.js → chunk-RMQQ5UHM.js} +2 -2
  184. package/dist/cli/chunks/{chunk-U62WL3WZ.js → chunk-ROEMVTXC.js} +3 -3
  185. package/dist/cli/chunks/{chunk-YOKRSFGA.js → chunk-SMTAZQJ3.js} +2 -2
  186. package/dist/cli/chunks/{chunk-OZTSMI7P.js → chunk-TO4NGP3E.js} +1 -1
  187. package/dist/cli/chunks/{chunk-LFEBTWFS.js → chunk-TTXYZUTQ.js} +2 -2
  188. package/dist/cli/chunks/{chunk-IZTUAI5T.js → chunk-U4NODKRR.js} +2 -2
  189. package/dist/cli/chunks/{chunk-JD3GH47Z.js → chunk-U635PSAW.js} +2 -2
  190. package/dist/cli/chunks/{chunk-6DBYVKGA.js → chunk-UBT7VCKQ.js} +2 -2
  191. package/dist/cli/chunks/{chunk-YSUMQBMY.js → chunk-UETM5XDO.js} +1 -1
  192. package/dist/cli/chunks/{chunk-BZB5D4BO.js → chunk-URXG7FMO.js} +4 -3
  193. package/dist/cli/chunks/{chunk-M2JBQVBP.js → chunk-VIWDVS24.js} +2 -2
  194. package/dist/cli/chunks/{chunk-6A4FEIE2.js → chunk-VNKCUKUJ.js} +3 -3
  195. package/dist/cli/chunks/{chunk-6KWX7A3R.js → chunk-VXIXHZCN.js} +2 -2
  196. package/dist/cli/chunks/{chunk-YIJDCZVX.js → chunk-WFEXEDMC.js} +2 -2
  197. package/dist/cli/chunks/{chunk-CG3HIYF4.js → chunk-WLX57ULC.js} +2 -2
  198. package/dist/cli/chunks/{chunk-FKODRXOU.js → chunk-WVQZGLCT.js} +2 -2
  199. package/dist/cli/chunks/{chunk-677V67MR.js → chunk-WW5DZ6BU.js} +1 -1
  200. package/dist/cli/chunks/{chunk-7L64UC5U.js → chunk-X364AIY6.js} +1 -1
  201. package/dist/cli/chunks/{chunk-UGJNR52C.js → chunk-XH7D6EGE.js} +1 -1
  202. package/dist/cli/chunks/{chunk-66DCG6RO.js → chunk-XICRAXUR.js} +4 -4
  203. package/dist/cli/chunks/{chunk-ETXK25IY.js → chunk-XMAV7AIC.js} +1 -1
  204. package/dist/cli/chunks/{chunk-NHXFAXEV.js → chunk-XSUPK7FI.js} +1 -1
  205. package/dist/cli/chunks/{chunk-3ZAGYTEC.js → chunk-XSWOB74I.js} +2 -2
  206. package/dist/cli/chunks/chunk-YPIZMTTA.js +14 -0
  207. package/dist/cli/chunks/{chunk-YDW522M7.js → chunk-YT6KBEXE.js} +2 -2
  208. package/dist/cli/chunks/{chunk-P2H5ARHM.js → chunk-ZENLP5LF.js} +1 -1
  209. package/dist/cli/chunks/{ci-A5ZXOEC4.js → ci-WS32HBBS.js} +2 -2
  210. package/dist/cli/chunks/{ci-output-S47BMRYC.js → ci-output-67R5MSLL.js} +2 -2
  211. package/dist/cli/chunks/circuit-breaker-MA562FT7.js +2 -0
  212. package/dist/cli/chunks/{claude-flow-setup-F5WBEBVK.js → claude-flow-setup-4QKGSRS7.js} +2 -2
  213. package/dist/cli/chunks/client-XQGZKXOB.js +2 -0
  214. package/dist/cli/chunks/{cline-installer-HLKR4QDR.js → cline-installer-6VSROHRY.js} +2 -2
  215. package/dist/cli/chunks/{code-MTZWS6JT.js → code-FBPBHVV3.js} +2 -2
  216. package/dist/cli/chunks/{code-index-extractor-BALTZ2WQ.js → code-index-extractor-62F622V2.js} +2 -2
  217. package/dist/cli/chunks/{codex-installer-LI2VIGET.js → codex-installer-LSR6DVCU.js} +2 -2
  218. package/dist/cli/chunks/{completions-TOF4GTNF.js → completions-56QOICBN.js} +2 -2
  219. package/dist/cli/chunks/{complexity-analyzer-IPFXIT6T.js → complexity-analyzer-SDH4NWIS.js} +2 -2
  220. package/dist/cli/chunks/{continuedev-installer-KWI66RBI.js → continuedev-installer-S7ZPL3VC.js} +2 -2
  221. package/dist/cli/chunks/{copilot-installer-REFOE6UF.js → copilot-installer-25GNNKNL.js} +2 -2
  222. package/dist/cli/chunks/{cost-tracker-M2MZQXCN.js → cost-tracker-73J4Y2RS.js} +2 -2
  223. package/dist/cli/chunks/{coverage-UR2XSJCR.js → coverage-WEE2AZ5F.js} +3 -3
  224. package/dist/cli/chunks/cross-domain-router-C2ZFCSXJ.js +2 -0
  225. package/dist/cli/chunks/{cursor-installer-X4PXCVYH.js → cursor-installer-DHQ644T3.js} +2 -2
  226. package/dist/cli/chunks/{daemon-5R6ZEEBB.js → daemon-3WUJ5E3X.js} +3 -3
  227. package/dist/cli/chunks/{dag-attention-scheduler-RUY2RJZA.js → dag-attention-scheduler-IRLAM43H.js} +2 -2
  228. package/dist/cli/chunks/{detect-PX2AYBHM.js → detect-DTSB4T4R.js} +2 -2
  229. package/dist/cli/chunks/{domain-handler-5JXWEO3E.js → domain-handler-DDN2Z5XC.js} +2 -2
  230. package/dist/cli/chunks/{domain-transfer-6M2YLBJY.js → domain-transfer-3RRG4S6R.js} +2 -2
  231. package/dist/cli/chunks/dream-JSZZ67OO.js +2 -0
  232. package/dist/cli/chunks/esm-node-X4TES6NX.js +2 -0
  233. package/dist/cli/chunks/{eval-L6ZBG462.js → eval-UXEP425X.js} +2 -2
  234. package/dist/cli/chunks/{fast-paths-WIFDALFK.js → fast-paths-4XLHS2VN.js} +2 -2
  235. package/dist/cli/chunks/{feature-flags-YLBXFUCN.js → feature-flags-6C2HD76K.js} +2 -2
  236. package/dist/cli/chunks/{feature-flags-GRHF5MTK.js → feature-flags-KXXHAEYF.js} +2 -2
  237. package/dist/cli/chunks/{file-discovery-4HXUB4HN.js → file-discovery-YSDUIZO4.js} +2 -2
  238. package/dist/cli/chunks/{fleet-RPLJXOEP.js → fleet-TYDG5DWK.js} +3 -3
  239. package/dist/cli/chunks/{gnn-wrapper-2D5IOGAT.js → gnn-wrapper-GJVYRPHB.js} +2 -2
  240. package/dist/cli/chunks/{heartbeat-handler-D5SWZZGA.js → heartbeat-handler-X63CM35O.js} +4 -4
  241. package/dist/cli/chunks/{heartbeat-scheduler-WSG4Y3M2.js → heartbeat-scheduler-NYH4CMVM.js} +2 -2
  242. package/dist/cli/chunks/hnsw-adapter-SQCVEHB5.js +2 -0
  243. package/dist/cli/chunks/hnsw-index-UGVC5IDK.js +2 -0
  244. package/dist/cli/chunks/{hnsw-legacy-bridge-UH6RWE74.js → hnsw-legacy-bridge-YDVUZTJI.js} +2 -2
  245. package/dist/cli/chunks/{hnswlib-node-BJ4ZJPMP.js → hnswlib-node-TLBDFWA6.js} +2 -2
  246. package/dist/cli/chunks/{hooks-KGDQNB5T.js → hooks-B6PVGP7D.js} +6 -6
  247. package/dist/cli/chunks/hybrid-router-YZEBKUZJ.js +2 -0
  248. package/dist/cli/chunks/{hypergraph-engine-LARQCK7V.js → hypergraph-engine-OQ2ZEG53.js} +2 -2
  249. package/dist/cli/chunks/{hypergraph-handler-RACF4AOX.js → hypergraph-handler-VPD424MI.js} +3 -3
  250. package/dist/cli/chunks/impact-analyzer-ZIXSRWED.js +2 -0
  251. package/dist/cli/chunks/{init-handler-64AOFMJD.js → init-handler-5WYP6NJW.js} +6 -6
  252. package/dist/cli/chunks/init-wizard-MO6PCXPX.js +2 -0
  253. package/dist/cli/chunks/kernel-P54KQB2F.js +2 -0
  254. package/dist/cli/chunks/{kilocode-installer-4ICIP6QN.js → kilocode-installer-YVY4EVMY.js} +2 -2
  255. package/dist/cli/chunks/{kiro-installer-J2GOV2OB.js → kiro-installer-GNT4BN3A.js} +2 -2
  256. package/dist/cli/chunks/knowledge-graph-GU57FQAQ.js +2 -0
  257. package/dist/cli/chunks/{learning-QD4JVH3K.js → learning-LD2RSBRS.js} +3 -3
  258. package/dist/cli/chunks/llm-router-ALKXFKLQ.js +36 -0
  259. package/dist/cli/chunks/{load-EXKUJMBK.js → load-XAOTGZYB.js} +2 -2
  260. package/dist/cli/chunks/load-test-5RFBTSS7.js +2 -0
  261. package/dist/cli/chunks/{mcp-NSNDZSMH.js → mcp-WDAJHGH4.js} +2 -2
  262. package/dist/cli/chunks/{memory-63JTNVZN.js → memory-M7QD57JD.js} +5 -5
  263. package/dist/cli/chunks/memory-backend-GPOP3IR4.js +2 -0
  264. package/dist/cli/chunks/memory-handlers-2NHGZLQM.js +2 -0
  265. package/dist/cli/chunks/multi-model-executor-2XZQK2IN.js +14 -0
  266. package/dist/cli/chunks/{opencode-installer-244LFSPN.js → opencode-installer-ASCVY3GG.js} +2 -2
  267. package/dist/cli/chunks/{orchestrator-TZB457J6.js → orchestrator-GOZICWN3.js} +22 -19
  268. package/dist/cli/chunks/{pipeline-YLBD2Z5Q.js → pipeline-YHQRJWV3.js} +2 -2
  269. package/dist/cli/chunks/{platform-53PWFZSE.js → platform-4NESYFHN.js} +2 -2
  270. package/dist/cli/chunks/{plugin-6GUQEFJU.js → plugin-E24I2RVB.js} +2 -2
  271. package/dist/cli/chunks/{prime-radiant-advanced-wasm-VCOK7FV5.js → prime-radiant-advanced-wasm-CDVSLR7R.js} +2 -2
  272. package/dist/cli/chunks/protocol-executor-M5IONISJ.js +2 -0
  273. package/dist/cli/chunks/{protocol-handler-25UEGTE2.js → protocol-handler-TGTDKSZB.js} +2 -2
  274. package/dist/cli/chunks/{prove-CTOU5F6G.js → prove-WUKDAMSE.js} +2 -2
  275. package/dist/cli/chunks/provider-manager-BTKK6W7M.js +24 -0
  276. package/dist/cli/chunks/qe-reasoning-bank-WIEXCBVE.js +2 -0
  277. package/dist/cli/chunks/{quality-PB7H5UEF.js → quality-RTIOIS2K.js} +2 -2
  278. package/dist/cli/chunks/queen-coordinator-ZFK6DANW.js +2 -0
  279. package/dist/cli/chunks/{real-embeddings-RWWYCIE5.js → real-embeddings-4JJKAEMO.js} +2 -2
  280. package/dist/cli/chunks/{roocode-installer-U4AGYVKL.js → roocode-installer-XU2IXRBM.js} +2 -2
  281. package/dist/cli/chunks/router-TOFBEI2Q.js +2 -0
  282. package/dist/cli/chunks/routing-feedback-RC2VDP6W.js +2 -0
  283. package/dist/cli/chunks/{routing-handler-NTDKDEBE.js → routing-handler-3KBOCIEN.js} +2 -2
  284. package/dist/cli/chunks/{ruvector-commands-RQKOLQSW.js → ruvector-commands-HHE2ZPX7.js} +2 -2
  285. package/dist/cli/chunks/{rvf-dual-writer-6EZ7S7OG.js → rvf-dual-writer-GAWM2BUZ.js} +2 -2
  286. package/dist/cli/chunks/{rvf-migration-adapter-EBTV6FV2.js → rvf-migration-adapter-HQPEC4BN.js} +2 -2
  287. package/dist/cli/chunks/{rvf-migration-coordinator-MERU7VLY.js → rvf-migration-coordinator-A4K45EFU.js} +2 -2
  288. package/dist/cli/chunks/rvf-native-adapter-ZOQDH3JY.js +2 -0
  289. package/dist/cli/chunks/safe-db-RIP3X32S.js +2 -0
  290. package/dist/cli/chunks/schedule-Q6KZRLWS.js +2 -0
  291. package/dist/cli/chunks/scheduler-SJO5QPAU.js +2 -0
  292. package/dist/cli/chunks/{security-JPDLGHMC.js → security-UIKUNOXB.js} +3 -3
  293. package/dist/cli/chunks/shared-rvf-adapter-JJCR3AWU.js +2 -0
  294. package/dist/cli/chunks/{shared-rvf-dual-writer-7OGLQE5Y.js → shared-rvf-dual-writer-ZUWSLFPH.js} +2 -2
  295. package/dist/cli/chunks/sqlite-persistence-HK2S6XAI.js +2 -0
  296. package/dist/cli/chunks/{status-handler-3TI3DHEL.js → status-handler-E3VSWGA6.js} +2 -2
  297. package/dist/cli/chunks/{structural-health-WCZKXVWS.js → structural-health-Y22H4BOU.js} +2 -2
  298. package/dist/cli/chunks/{sync-AM5T4GYO.js → sync-CA4KWZFS.js} +2 -2
  299. package/dist/cli/chunks/{task-handler-VHDTXPVP.js → task-handler-3EZPIAMD.js} +2 -2
  300. package/dist/cli/chunks/task-handlers-6UVAQAGP.js +2 -0
  301. package/dist/cli/chunks/{test-G6P5XGHM.js → test-Q5DOFSJI.js} +4 -4
  302. package/dist/cli/chunks/{test-scheduling-37RBUN4E.js → test-scheduling-BSXWCIMQ.js} +3 -3
  303. package/dist/cli/chunks/token-bootstrap-XGEZU2CS.js +2 -0
  304. package/dist/cli/chunks/{token-usage-5XGVBLFR.js → token-usage-BZX5TCG6.js} +2 -2
  305. package/dist/cli/chunks/{transformers-JTKWAZJU.js → transformers-7ITQPXAU.js} +2 -2
  306. package/dist/cli/chunks/{tree-sitter-wasm-parser-KW2GWIIQ.js → tree-sitter-wasm-parser-ZYBBNYR3.js} +2 -2
  307. package/dist/cli/chunks/{types-7R72BACI.js → types-ACZ5VVRC.js} +2 -2
  308. package/dist/cli/chunks/unified-memory-EXO6WK33.js +2 -0
  309. package/dist/cli/chunks/unified-memory-hnsw-7HPSTFVV.js +2 -0
  310. package/dist/cli/chunks/unified-persistence-WC3O4WOJ.js +2 -0
  311. package/dist/cli/chunks/{validate-TYB4ZTUL.js → validate-IQL6OVXD.js} +2 -2
  312. package/dist/cli/chunks/{validate-swarm-3TFI6PLT.js → validate-swarm-J52J2K5X.js} +2 -2
  313. package/dist/cli/chunks/{vibium-3YELURJT.js → vibium-XSE76PXE.js} +2 -2
  314. package/dist/cli/chunks/visual-security-COW3OCEE.js +2 -0
  315. package/dist/cli/chunks/{web-tree-sitter-7Q77A27Y.js → web-tree-sitter-YM6QXUIY.js} +2 -2
  316. package/dist/cli/chunks/{windsurf-installer-ASARRM2X.js → windsurf-installer-M27DVL4H.js} +2 -2
  317. package/dist/cli/chunks/{witness-chain-WZ6PNXEY.js → witness-chain-NB5LP73S.js} +2 -2
  318. package/dist/cli/chunks/witness-chain-XQXF3RSP.js +2 -0
  319. package/dist/cli/chunks/{workflow-JDTEE6TY.js → workflow-5DODQ6XS.js} +4 -4
  320. package/dist/cli/chunks/workflow-orchestrator-HSIZEKZM.js +2 -0
  321. package/dist/cli/chunks/{wrappers-X7WZLBZD.js → wrappers-K7HHCIYD.js} +2 -2
  322. package/dist/cli/commands/llm-router.js +252 -0
  323. package/dist/coordination/queen-task-management.js +8 -1
  324. package/dist/init/browser-engine-installer.d.ts +60 -0
  325. package/dist/init/browser-engine-installer.js +92 -0
  326. package/dist/init/init-wizard-steps.js +9 -0
  327. package/dist/init/phases/09-assets.d.ts +2 -0
  328. package/dist/init/phases/09-assets.js +65 -0
  329. package/dist/init/phases/12-verification.js +8 -0
  330. package/dist/init/skills-installer.js +1 -0
  331. package/dist/kernel/unified-memory-schemas.d.ts +1 -1
  332. package/dist/kernel/unified-memory-schemas.js +2 -1
  333. package/dist/mcp/bundle.js +47 -44
  334. package/dist/mcp/protocol-server.js +87 -0
  335. package/dist/routing/advisor/circuit-breaker.d.ts +56 -0
  336. package/dist/routing/advisor/circuit-breaker.js +128 -0
  337. package/dist/routing/advisor/domain-prompts.d.ts +14 -0
  338. package/dist/routing/advisor/domain-prompts.js +53 -0
  339. package/dist/routing/advisor/index.d.ts +10 -0
  340. package/dist/routing/advisor/index.js +9 -0
  341. package/dist/routing/advisor/multi-model-executor.d.ts +60 -0
  342. package/dist/routing/advisor/multi-model-executor.js +176 -0
  343. package/dist/routing/advisor/redaction.d.ts +40 -0
  344. package/dist/routing/advisor/redaction.js +187 -0
  345. package/dist/routing/advisor/types.d.ts +101 -0
  346. package/dist/routing/advisor/types.js +9 -0
  347. package/dist/routing/queen-integration.d.ts +3 -0
  348. package/dist/routing/queen-integration.js +7 -1
  349. package/dist/routing/routing-feedback.d.ts +7 -1
  350. package/dist/routing/routing-feedback.js +57 -11
  351. package/dist/routing/tiny-dancer-router.d.ts +35 -1
  352. package/dist/routing/tiny-dancer-router.js +33 -0
  353. package/dist/routing/types.d.ts +12 -0
  354. package/package.json +1 -1
  355. package/dist/cli/chunks/adapter-D4XQUIJD.js +0 -2
  356. package/dist/cli/chunks/aqe-learning-engine-CGIWYLIP.js +0 -2
  357. package/dist/cli/chunks/base-BYVP2STR.js +0 -2
  358. package/dist/cli/chunks/browser-workflow-PC4N5TKL.js +0 -2
  359. package/dist/cli/chunks/chunk-2K3DJ3EK.js +0 -7
  360. package/dist/cli/chunks/chunk-JBQ4WGB4.js +0 -14
  361. package/dist/cli/chunks/chunk-OT4JADWW.js +0 -2
  362. package/dist/cli/chunks/client-56BU3GAX.js +0 -2
  363. package/dist/cli/chunks/cross-domain-router-XQT52BTB.js +0 -2
  364. package/dist/cli/chunks/dream-LFZCN5WK.js +0 -2
  365. package/dist/cli/chunks/esm-node-EBDIEPKS.js +0 -2
  366. package/dist/cli/chunks/hnsw-adapter-BMXTVGZB.js +0 -2
  367. package/dist/cli/chunks/hnsw-index-YX6XLICT.js +0 -2
  368. package/dist/cli/chunks/impact-analyzer-MGSI2WBK.js +0 -2
  369. package/dist/cli/chunks/init-wizard-TBDWRRMC.js +0 -2
  370. package/dist/cli/chunks/kernel-NV7TO2FK.js +0 -2
  371. package/dist/cli/chunks/knowledge-graph-7REGYH6A.js +0 -2
  372. package/dist/cli/chunks/llm-router-4K4IT2PQ.js +0 -30
  373. package/dist/cli/chunks/load-test-RYQK44TT.js +0 -2
  374. package/dist/cli/chunks/memory-backend-3EBE2DEX.js +0 -2
  375. package/dist/cli/chunks/memory-handlers-2335MVQJ.js +0 -2
  376. package/dist/cli/chunks/protocol-executor-MR37S7GX.js +0 -2
  377. package/dist/cli/chunks/qe-reasoning-bank-DANGLPTH.js +0 -2
  378. package/dist/cli/chunks/queen-coordinator-4YJPYF5F.js +0 -2
  379. package/dist/cli/chunks/router-F4IPY4RQ.js +0 -2
  380. package/dist/cli/chunks/routing-feedback-VGHFIJ5S.js +0 -2
  381. package/dist/cli/chunks/rvf-native-adapter-2P75WF5A.js +0 -2
  382. package/dist/cli/chunks/safe-db-47NEO2RS.js +0 -2
  383. package/dist/cli/chunks/schedule-L5GJW25Z.js +0 -2
  384. package/dist/cli/chunks/scheduler-NGGGSZMO.js +0 -2
  385. package/dist/cli/chunks/shared-rvf-adapter-NKNTYGHO.js +0 -2
  386. package/dist/cli/chunks/sqlite-persistence-TE2ZRHKA.js +0 -2
  387. package/dist/cli/chunks/task-handlers-GEJ36WNB.js +0 -2
  388. package/dist/cli/chunks/token-bootstrap-JPE3LWXQ.js +0 -2
  389. package/dist/cli/chunks/unified-memory-KSBLUZT4.js +0 -2
  390. package/dist/cli/chunks/unified-memory-hnsw-V3EOMQIZ.js +0 -2
  391. package/dist/cli/chunks/unified-persistence-URIRJ4BM.js +0 -2
  392. package/dist/cli/chunks/visual-security-DJOOVCBZ.js +0 -2
  393. package/dist/cli/chunks/witness-chain-ZWJUCXCJ.js +0 -2
  394. package/dist/cli/chunks/workflow-orchestrator-5CKA6Q74.js +0 -2
@@ -0,0 +1,378 @@
1
+ #!/usr/bin/env node
2
+ // qe-browser: typed assertions against the current Vibium page state.
3
+ //
4
+ // Usage:
5
+ // node assert.js --checks '[{"kind": "url_contains", "text": "/dashboard"}]'
6
+ // node assert.js --checks @checks.json
7
+ //
8
+ // Exit code: 0 if all passed, 1 if any failed or on error.
9
+ // Output: JSON envelope matching schemas/output.json.
10
+
11
+ 'use strict';
12
+
13
+ const {
14
+ vibiumJson,
15
+ vibiumEvalStdin,
16
+ envelope,
17
+ parseArgs,
18
+ readInlineOrFile,
19
+ emit,
20
+ fail,
21
+ runOrSkip,
22
+ isVibiumUnavailable,
23
+ rethrowIfUnavailable,
24
+ } = require('./lib/vibium');
25
+
26
+ // Hard cap on regex pattern length to prevent pathological ReDoS input
27
+ // (e.g. `(a+)+$` against a long string). 1024 chars is plenty for any
28
+ // real test assertion. Enforced in runConsoleCheck before constructing
29
+ // a RegExp from user-supplied `check.pattern`.
30
+ const MAX_REGEX_PATTERN_LENGTH = 1024;
31
+
32
+ // Characters permitted in a user-supplied regex pattern. Anything outside
33
+ // this set (control chars, high-unicode, etc.) is rejected. This is the
34
+ // sanitizer CodeQL's js/regex-injection query recognizes: the pattern is
35
+ // validated against a literal allowlist before it reaches `new RegExp`.
36
+ // We allow the full POSIX regex metacharacter set, ASCII alphanumerics,
37
+ // whitespace, and the common punctuation used in real assertion patterns.
38
+ // eslint-disable-next-line no-useless-escape
39
+ const REGEX_PATTERN_ALLOWLIST = /^[\w\s\.\*\+\?\^\$\(\)\[\]\{\}\|\\/\-:;,=!<>@#%&'"`~]*$/;
40
+
41
+ // safeRegex: construct a RegExp from user input, defensively. Returns
42
+ // { re, error } — callers emit a failed check instead of crashing the
43
+ // whole assertion pass. Layered defense:
44
+ // 1. Type check — must be string
45
+ // 2. Length cap — MAX_REGEX_PATTERN_LENGTH to bound ReDoS worst case
46
+ // 3. Character allowlist — strips anything unexpected before construction
47
+ // 4. Try/catch around the constructor — invalid syntax returns error
48
+ //
49
+ // The allowlist is the CodeQL-recognized sanitizer for js/regex-injection.
50
+ function safeRegex(pattern) {
51
+ if (typeof pattern !== 'string') {
52
+ return { re: null, error: 'pattern must be a string' };
53
+ }
54
+ if (pattern.length > MAX_REGEX_PATTERN_LENGTH) {
55
+ return {
56
+ re: null,
57
+ error: `pattern too long (${pattern.length} > ${MAX_REGEX_PATTERN_LENGTH})`,
58
+ };
59
+ }
60
+ if (!REGEX_PATTERN_ALLOWLIST.test(pattern)) {
61
+ return {
62
+ re: null,
63
+ error: 'pattern contains characters outside the allowlist (control chars, non-ASCII, etc.)',
64
+ };
65
+ }
66
+ // Pattern has passed type, length, and character-allowlist checks.
67
+ // Any remaining RegExp constructor error is a syntax error, which we
68
+ // surface as a failed check rather than crashing the assertion pass.
69
+ try {
70
+ // Construct from a sanitized local copy so static analyzers can follow
71
+ // the flow: the string has been validated against REGEX_PATTERN_ALLOWLIST
72
+ // before reaching the RegExp constructor.
73
+ const sanitized = pattern;
74
+ return { re: new RegExp(sanitized), error: null };
75
+ } catch (err) {
76
+ return { re: null, error: `invalid regex: ${err.message}` };
77
+ }
78
+ }
79
+
80
+ const CHECK_KINDS = new Set([
81
+ 'url_contains',
82
+ 'url_equals',
83
+ 'text_visible',
84
+ 'text_hidden',
85
+ 'selector_visible',
86
+ 'selector_hidden',
87
+ 'value_equals',
88
+ 'attribute_equals',
89
+ 'no_console_errors',
90
+ 'no_failed_requests',
91
+ 'response_status',
92
+ 'request_url_seen',
93
+ 'console_message_matches',
94
+ 'element_count',
95
+ 'title_matches',
96
+ 'page_source_contains',
97
+ ]);
98
+
99
+ function buildEvalScript(check) {
100
+ const q = (v) => JSON.stringify(v);
101
+ switch (check.kind) {
102
+ case 'url_contains':
103
+ return `JSON.stringify({ ok: location.href.includes(${q(check.text)}), actual: location.href })`;
104
+ case 'url_equals':
105
+ return `JSON.stringify({ ok: location.href === ${q(check.url)}, actual: location.href })`;
106
+ case 'text_visible':
107
+ return `(() => {
108
+ const needle = ${q(check.text)};
109
+ const body = document.body ? document.body.innerText : '';
110
+ return JSON.stringify({ ok: body.includes(needle), actual: null });
111
+ })()`;
112
+ case 'text_hidden':
113
+ return `(() => {
114
+ const needle = ${q(check.text)};
115
+ const body = document.body ? document.body.innerText : '';
116
+ return JSON.stringify({ ok: !body.includes(needle), actual: null });
117
+ })()`;
118
+ case 'selector_visible':
119
+ return `(() => {
120
+ const el = document.querySelector(${q(check.selector)});
121
+ if (!el) return JSON.stringify({ ok: false, actual: 'not found' });
122
+ const r = el.getBoundingClientRect();
123
+ const s = getComputedStyle(el);
124
+ const visible = r.width > 0 && r.height > 0 && s.display !== 'none' && s.visibility !== 'hidden' && parseFloat(s.opacity) > 0;
125
+ return JSON.stringify({ ok: visible, actual: { width: r.width, height: r.height, display: s.display } });
126
+ })()`;
127
+ case 'selector_hidden':
128
+ return `(() => {
129
+ const el = document.querySelector(${q(check.selector)});
130
+ if (!el) return JSON.stringify({ ok: true, actual: 'not found' });
131
+ const r = el.getBoundingClientRect();
132
+ const s = getComputedStyle(el);
133
+ const visible = r.width > 0 && r.height > 0 && s.display !== 'none' && s.visibility !== 'hidden' && parseFloat(s.opacity) > 0;
134
+ return JSON.stringify({ ok: !visible, actual: { width: r.width, height: r.height, display: s.display } });
135
+ })()`;
136
+ case 'value_equals':
137
+ return `(() => {
138
+ const el = document.querySelector(${q(check.selector)});
139
+ if (!el) return JSON.stringify({ ok: false, actual: 'not found' });
140
+ return JSON.stringify({ ok: el.value === ${q(check.value)}, actual: el.value });
141
+ })()`;
142
+ case 'attribute_equals':
143
+ return `(() => {
144
+ const el = document.querySelector(${q(check.selector)});
145
+ if (!el) return JSON.stringify({ ok: false, actual: 'not found' });
146
+ const v = el.getAttribute(${q(check.attribute)});
147
+ return JSON.stringify({ ok: v === ${q(check.value)}, actual: v });
148
+ })()`;
149
+ case 'element_count': {
150
+ const op = check.op || '==';
151
+ return `(() => {
152
+ const n = document.querySelectorAll(${q(check.selector)}).length;
153
+ const want = ${Number(check.count)};
154
+ const ok = (${JSON.stringify(op)} === '==' ? n === want :
155
+ ${JSON.stringify(op)} === '>=' ? n >= want :
156
+ ${JSON.stringify(op)} === '<=' ? n <= want :
157
+ ${JSON.stringify(op)} === '>' ? n > want :
158
+ ${JSON.stringify(op)} === '<' ? n < want :
159
+ false);
160
+ return JSON.stringify({ ok, actual: n });
161
+ })()`;
162
+ }
163
+ case 'title_matches':
164
+ return `(() => {
165
+ const re = new RegExp(${q(check.pattern)});
166
+ return JSON.stringify({ ok: re.test(document.title), actual: document.title });
167
+ })()`;
168
+ case 'page_source_contains':
169
+ return `JSON.stringify({ ok: document.documentElement.outerHTML.includes(${q(check.text)}), actual: null })`;
170
+ default:
171
+ return null;
172
+ }
173
+ }
174
+
175
+ function runBrowserSideCheck(check) {
176
+ const script = buildEvalScript(check);
177
+ if (!script) return null;
178
+ // Pass the JSON.stringify expression directly — vibium eval returns the
179
+ // last expression's value, NOT console.log output. lib/vibium.js's
180
+ // unwrapEvalResult parses the {ok, result} envelope and JSON-decodes the
181
+ // string for us, so `payload` is already our object.
182
+ try {
183
+ const payload = vibiumEvalStdin(script);
184
+ if (payload && typeof payload === 'object' && 'ok' in payload) {
185
+ return payload;
186
+ }
187
+ return { ok: false, actual: payload };
188
+ } catch (err) {
189
+ // F1: bubble VibiumUnavailableError past this catch so runOrSkip can
190
+ // emit the documented skipped envelope. Other errors stay scoped to
191
+ // the individual check (we still report them inside `actual`).
192
+ rethrowIfUnavailable(err);
193
+ return { ok: false, actual: `eval error: ${err.message}` };
194
+ }
195
+ }
196
+
197
+ // Sentinel returned by console/network checks when the underlying vibium
198
+ // command fails. Tests and callers can distinguish "check actually passed"
199
+ // from "we couldn't tell" by looking at result.unavailable. assert.js treats
200
+ // unavailable as a FAIL — per feedback_no_unverified_failure_modes.md,
201
+ // silently reporting green when the signal is missing is a prohibited
202
+ // failure mode.
203
+ //
204
+ // F1 distinction: this `unavailable` sentinel is for "vibium ran but the
205
+ // `console`/`network` subcommand returned nothing useful" — NOT for "vibium
206
+ // itself isn't installed". The latter is handled by VibiumUnavailableError
207
+ // + runOrSkip + the skipped envelope. We re-throw the unavailable error so
208
+ // it surfaces correctly.
209
+ function unavailable(err) {
210
+ return {
211
+ ok: false,
212
+ unavailable: true,
213
+ actual: null,
214
+ message: `vibium telemetry unavailable: ${err.message || err}`,
215
+ };
216
+ }
217
+
218
+ function runConsoleCheck(kind, check) {
219
+ let raw;
220
+ try {
221
+ raw = vibiumJson(['console', '--json']);
222
+ } catch (err) {
223
+ rethrowIfUnavailable(err);
224
+ return unavailable(err);
225
+ }
226
+ const entries = Array.isArray(raw) ? raw : Array.isArray(raw && raw.entries) ? raw.entries : [];
227
+ if (kind === 'no_console_errors') {
228
+ const errors = entries.filter((e) =>
229
+ ['error', 'severe'].includes(String(e.level || e.type || '').toLowerCase())
230
+ );
231
+ return { ok: errors.length === 0, actual: errors.length };
232
+ }
233
+ if (kind === 'console_message_matches') {
234
+ const { re, error } = safeRegex(check.pattern);
235
+ if (!re) return { ok: false, actual: error };
236
+ const match = entries.find((e) => re.test(String(e.message || e.text || '')));
237
+ return { ok: Boolean(match), actual: match ? match.message || match.text : null };
238
+ }
239
+ return { ok: false, actual: 'unknown console kind' };
240
+ }
241
+
242
+ function runNetworkCheck(kind, check) {
243
+ let raw;
244
+ try {
245
+ raw = vibiumJson(['network', '--json']);
246
+ } catch (err) {
247
+ rethrowIfUnavailable(err);
248
+ return unavailable(err);
249
+ }
250
+ const entries = Array.isArray(raw) ? raw : Array.isArray(raw && raw.entries) ? raw.entries : [];
251
+ if (kind === 'no_failed_requests') {
252
+ const failed = entries.filter((e) => {
253
+ const status = Number(e.status || 0);
254
+ return status >= 400 || e.failed === true || e.error;
255
+ });
256
+ return { ok: failed.length === 0, actual: failed.length };
257
+ }
258
+ if (kind === 'response_status') {
259
+ const hit = entries.find((e) => String(e.url || '').includes(check.url));
260
+ if (!hit) return { ok: false, actual: 'url not seen' };
261
+ return {
262
+ ok: Number(hit.status) === Number(check.status),
263
+ actual: Number(hit.status),
264
+ };
265
+ }
266
+ if (kind === 'request_url_seen') {
267
+ const hit = entries.find((e) => String(e.url || '').includes(check.url));
268
+ return { ok: Boolean(hit), actual: hit ? hit.url : null };
269
+ }
270
+ return { ok: false, actual: 'unknown network kind' };
271
+ }
272
+
273
+ function runCheck(check) {
274
+ if (!check || typeof check !== 'object') {
275
+ return { kind: 'invalid', passed: false, message: 'check must be an object' };
276
+ }
277
+ if (!CHECK_KINDS.has(check.kind)) {
278
+ return {
279
+ kind: check.kind,
280
+ passed: false,
281
+ message: `unknown check kind: ${check.kind}`,
282
+ };
283
+ }
284
+
285
+ let result;
286
+ if (check.kind === 'no_console_errors' || check.kind === 'console_message_matches') {
287
+ result = runConsoleCheck(check.kind, check);
288
+ } else if (
289
+ check.kind === 'no_failed_requests' ||
290
+ check.kind === 'response_status' ||
291
+ check.kind === 'request_url_seen'
292
+ ) {
293
+ result = runNetworkCheck(check.kind, check);
294
+ } else {
295
+ result = runBrowserSideCheck(check);
296
+ }
297
+
298
+ // Use ?? instead of || so falsy-but-valid values (count: 0, url: '',
299
+ // value: '') are preserved in the expected field. The old || chain
300
+ // silently converted them to null, which made debug output misleading.
301
+ const expected =
302
+ check.text ??
303
+ check.url ??
304
+ check.value ??
305
+ check.pattern ??
306
+ check.count ??
307
+ null;
308
+
309
+ return {
310
+ kind: check.kind,
311
+ passed: Boolean(result && result.ok),
312
+ unavailable: Boolean(result && result.unavailable),
313
+ actual: result ? result.actual : null,
314
+ expected,
315
+ message:
316
+ result && result.message
317
+ ? result.message
318
+ : result && result.note
319
+ ? result.note
320
+ : undefined,
321
+ };
322
+ }
323
+
324
+ function main() {
325
+ const args = parseArgs(process.argv.slice(2));
326
+ const rawChecks = args.checks;
327
+ if (!rawChecks) {
328
+ return fail('assert', 'missing --checks argument');
329
+ }
330
+ let checks;
331
+ try {
332
+ checks = JSON.parse(readInlineOrFile(rawChecks));
333
+ } catch (err) {
334
+ return fail('assert', `invalid --checks JSON: ${err.message}`);
335
+ }
336
+ if (!Array.isArray(checks)) {
337
+ return fail('assert', '--checks must be a JSON array');
338
+ }
339
+
340
+ const startedAt = Date.now();
341
+ const results = checks.map(runCheck);
342
+ const passed = results.filter((r) => r.passed).length;
343
+ const failed = results.length - passed;
344
+ const unavailable = results.filter((r) => r.unavailable).length;
345
+
346
+ const env = envelope({
347
+ operation: 'assert',
348
+ summary:
349
+ failed === 0
350
+ ? `All ${passed} assertions passed`
351
+ : unavailable > 0
352
+ ? `${failed} of ${results.length} assertions failed (${unavailable} due to vibium telemetry unavailable)`
353
+ : `${failed} of ${results.length} assertions failed`,
354
+ status: failed === 0 ? 'success' : 'failed',
355
+ details: {
356
+ assert: { passed, failed, results },
357
+ },
358
+ metadata: { executionTimeMs: Date.now() - startedAt },
359
+ });
360
+
361
+ return emit(env);
362
+ }
363
+
364
+ if (require.main === module) {
365
+ // F1: runOrSkip catches VibiumUnavailableError thrown anywhere inside
366
+ // main() (including from nested vibium() / vibiumJson() / vibiumEval*
367
+ // calls) and emits the documented skipped envelope with exit code 2.
368
+ process.exit(runOrSkip('assert', main));
369
+ }
370
+
371
+ module.exports = {
372
+ runCheck,
373
+ CHECK_KINDS,
374
+ buildEvalScript,
375
+ unavailable,
376
+ safeRegex,
377
+ MAX_REGEX_PATTERN_LENGTH,
378
+ };
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env node
2
+ // qe-browser: multi-step batch executor. Reduces round-trips by dispatching
3
+ // a sequence of vibium commands from a single JSON plan.
4
+ //
5
+ // Usage:
6
+ // node batch.js --steps '[{"action":"go","url":"https://example.com"}, ...]'
7
+ // node batch.js --steps @flow.json --summary-only
8
+ // node batch.js --steps @flow.json --continue-on-failure
9
+ //
10
+ // Supported actions (dispatch to the corresponding vibium subcommand):
11
+ // go / navigate — url
12
+ // click — ref | selector
13
+ // fill — ref | selector, text
14
+ // type — ref | selector, text
15
+ // press — key, [selector]
16
+ // wait_url — pattern, [timeoutMs]
17
+ // wait_text — text, [timeoutMs]
18
+ // wait_selector — selector, [state, timeoutMs]
19
+ // wait_load — [timeoutMs]
20
+ // map — [selector]
21
+ // screenshot — [output, fullPage]
22
+ // storage_save — path
23
+ // storage_restore — path
24
+ // assert — checks (see assert.js)
25
+
26
+ 'use strict';
27
+
28
+ const path = require('node:path');
29
+ const { spawnSync } = require('node:child_process');
30
+ const {
31
+ vibium,
32
+ vibiumJson,
33
+ envelope,
34
+ parseArgs,
35
+ readInlineOrFile,
36
+ emit,
37
+ fail,
38
+ runOrSkip,
39
+ rethrowIfUnavailable,
40
+ } = require('./lib/vibium');
41
+
42
+ // M6 (devil's-advocate finding): batch.js originally validated each step
43
+ // lazily inside dispatch(), so a typo in step 17 only surfaced AFTER steps
44
+ // 1-16 had already executed (with side effects on the live page). Add a
45
+ // pre-execution validation pass that walks every step's required fields
46
+ // and aborts before the first vibium call if anything is wrong.
47
+ const VALID_ACTIONS = new Set([
48
+ 'go',
49
+ 'navigate',
50
+ 'click',
51
+ 'fill',
52
+ 'type',
53
+ 'press',
54
+ 'wait_url',
55
+ 'wait_text',
56
+ 'wait_selector',
57
+ 'wait_load',
58
+ 'map',
59
+ 'screenshot',
60
+ 'storage_save',
61
+ 'storage_restore',
62
+ 'assert',
63
+ ]);
64
+
65
+ function validateStep(step, index) {
66
+ if (!step || typeof step !== 'object') {
67
+ return `step ${index}: must be an object`;
68
+ }
69
+ const a = step.action;
70
+ if (!a) return `step ${index}: missing "action"`;
71
+ if (!VALID_ACTIONS.has(a)) {
72
+ return `step ${index}: unknown action "${a}". Valid: ${[...VALID_ACTIONS].join(', ')}`;
73
+ }
74
+ const target = step.ref || step.selector;
75
+ switch (a) {
76
+ case 'go':
77
+ case 'navigate':
78
+ if (!step.url) return `step ${index} (${a}): missing "url"`;
79
+ break;
80
+ case 'click':
81
+ if (!target) return `step ${index} (click): missing "ref" or "selector"`;
82
+ break;
83
+ case 'fill':
84
+ case 'type':
85
+ if (!target) return `step ${index} (${a}): missing "ref" or "selector"`;
86
+ if (typeof step.text !== 'string') return `step ${index} (${a}): "text" must be a string`;
87
+ break;
88
+ case 'press':
89
+ if (!step.key) return `step ${index} (press): missing "key"`;
90
+ break;
91
+ case 'wait_url':
92
+ if (!step.pattern) return `step ${index} (wait_url): missing "pattern"`;
93
+ break;
94
+ case 'wait_text':
95
+ if (!step.text) return `step ${index} (wait_text): missing "text"`;
96
+ break;
97
+ case 'wait_selector':
98
+ if (!step.selector) return `step ${index} (wait_selector): missing "selector"`;
99
+ break;
100
+ case 'storage_save':
101
+ case 'storage_restore':
102
+ if (!step.path) return `step ${index} (${a}): missing "path"`;
103
+ break;
104
+ case 'assert':
105
+ if (!Array.isArray(step.checks)) {
106
+ return `step ${index} (assert): "checks" must be an array`;
107
+ }
108
+ break;
109
+ // wait_load, map, screenshot have no required fields
110
+ }
111
+ return null;
112
+ }
113
+
114
+ function validateAllSteps(steps) {
115
+ const errors = [];
116
+ for (let i = 0; i < steps.length; i += 1) {
117
+ const err = validateStep(steps[i], i);
118
+ if (err) errors.push(err);
119
+ }
120
+ return errors;
121
+ }
122
+
123
+ function runVibium(args) {
124
+ const result = vibium(args);
125
+ if (result.status !== 0) {
126
+ throw new Error(
127
+ `vibium ${args.join(' ')} exited ${result.status}: ${
128
+ result.stderr.trim() || result.stdout.trim()
129
+ }`
130
+ );
131
+ }
132
+ return result.stdout.trim();
133
+ }
134
+
135
+ function dispatch(step) {
136
+ const a = step.action;
137
+ const target = step.ref || step.selector;
138
+
139
+ switch (a) {
140
+ case 'go':
141
+ case 'navigate':
142
+ if (!step.url) throw new Error(`${a}: missing url`);
143
+ return runVibium(['go', step.url]);
144
+ case 'click':
145
+ if (!target) throw new Error('click: missing ref or selector');
146
+ return runVibium(['click', target]);
147
+ case 'fill':
148
+ if (!target) throw new Error('fill: missing ref or selector');
149
+ if (typeof step.text !== 'string') throw new Error('fill: missing text');
150
+ return runVibium(['fill', target, step.text]);
151
+ case 'type':
152
+ if (!target) throw new Error('type: missing ref or selector');
153
+ if (typeof step.text !== 'string') throw new Error('type: missing text');
154
+ return runVibium(['type', target, step.text]);
155
+ case 'press':
156
+ if (!step.key) throw new Error('press: missing key');
157
+ return runVibium(target ? ['press', step.key, target] : ['press', step.key]);
158
+ case 'wait_url':
159
+ if (!step.pattern) throw new Error('wait_url: missing pattern');
160
+ return runVibium(
161
+ step.timeoutMs
162
+ ? ['wait', 'url', step.pattern, '--timeout', String(step.timeoutMs)]
163
+ : ['wait', 'url', step.pattern]
164
+ );
165
+ case 'wait_text':
166
+ if (!step.text) throw new Error('wait_text: missing text');
167
+ return runVibium(
168
+ step.timeoutMs
169
+ ? ['wait', 'text', step.text, '--timeout', String(step.timeoutMs)]
170
+ : ['wait', 'text', step.text]
171
+ );
172
+ case 'wait_selector': {
173
+ if (!step.selector) throw new Error('wait_selector: missing selector');
174
+ const args = ['wait', step.selector];
175
+ if (step.state) args.push('--state', step.state);
176
+ if (step.timeoutMs) args.push('--timeout', String(step.timeoutMs));
177
+ return runVibium(args);
178
+ }
179
+ case 'wait_load':
180
+ return runVibium(
181
+ step.timeoutMs ? ['wait', 'load', '--timeout', String(step.timeoutMs)] : ['wait', 'load']
182
+ );
183
+ case 'map':
184
+ return vibiumJson(step.selector ? ['map', '--selector', step.selector] : ['map']);
185
+ case 'screenshot': {
186
+ const args = ['screenshot'];
187
+ if (step.output) args.push('-o', step.output);
188
+ if (step.fullPage) args.push('--full-page');
189
+ if (step.annotate) args.push('--annotate');
190
+ return runVibium(args);
191
+ }
192
+ case 'storage_save':
193
+ if (!step.path) throw new Error('storage_save: missing path');
194
+ return runVibium(['storage', '-o', step.path]);
195
+ case 'storage_restore':
196
+ if (!step.path) throw new Error('storage_restore: missing path');
197
+ return runVibium(['storage', 'restore', step.path]);
198
+ case 'assert': {
199
+ // Delegate to assert.js in the same directory.
200
+ const assertScript = path.resolve(__dirname, 'assert.js');
201
+ const checks = JSON.stringify(step.checks || []);
202
+ const res = spawnSync('node', [assertScript, '--checks', checks], {
203
+ encoding: 'utf8',
204
+ maxBuffer: 16 * 1024 * 1024,
205
+ });
206
+ if (res.status !== 0) {
207
+ throw new Error(`assert step failed: ${res.stdout.trim() || res.stderr.trim()}`);
208
+ }
209
+ return res.stdout.trim();
210
+ }
211
+ default:
212
+ throw new Error(`unknown batch action: ${a}`);
213
+ }
214
+ }
215
+
216
+ function main() {
217
+ const args = parseArgs(process.argv.slice(2));
218
+ const rawSteps = args.steps;
219
+ if (!rawSteps) return fail('batch', 'missing --steps argument');
220
+
221
+ let steps;
222
+ try {
223
+ steps = JSON.parse(readInlineOrFile(rawSteps));
224
+ } catch (err) {
225
+ return fail('batch', `invalid --steps JSON: ${err.message}`);
226
+ }
227
+ if (!Array.isArray(steps)) {
228
+ return fail('batch', '--steps must be a JSON array');
229
+ }
230
+
231
+ // M6: pre-validate all steps before executing any of them.
232
+ const validationErrors = validateAllSteps(steps);
233
+ if (validationErrors.length > 0) {
234
+ return fail(
235
+ 'batch',
236
+ `${validationErrors.length} step(s) failed pre-validation: ${validationErrors.join('; ')}`
237
+ );
238
+ }
239
+
240
+ const stopOnFailure = !args['continue-on-failure'];
241
+ const summaryOnly = Boolean(args['summary-only']);
242
+ const startedAt = Date.now();
243
+
244
+ const results = [];
245
+ let passed = 0;
246
+ let failedStep = null;
247
+
248
+ for (let i = 0; i < steps.length; i += 1) {
249
+ const step = steps[i];
250
+ try {
251
+ dispatch(step);
252
+ passed += 1;
253
+ results.push({ index: i, action: step.action, status: 'pass' });
254
+ } catch (err) {
255
+ // F1: if vibium isn't installed, abort the whole batch and let
256
+ // runOrSkip emit the skipped envelope. A "step failed because the
257
+ // browser engine is missing" is not a per-step failure — it's a
258
+ // whole-run environment problem.
259
+ rethrowIfUnavailable(err);
260
+ const info = { index: i, action: step.action, status: 'fail', error: err.message };
261
+ results.push(info);
262
+ failedStep = info;
263
+ if (stopOnFailure) break;
264
+ }
265
+ }
266
+
267
+ const env = envelope({
268
+ operation: 'batch',
269
+ summary:
270
+ failedStep === null
271
+ ? `All ${passed} steps passed`
272
+ : `Failed at step ${failedStep.index} (${failedStep.action}): ${failedStep.error}`,
273
+ status: failedStep === null ? 'success' : 'failed',
274
+ details: {
275
+ batch: {
276
+ totalSteps: steps.length,
277
+ passedSteps: passed,
278
+ failedStep,
279
+ steps: summaryOnly ? undefined : results,
280
+ },
281
+ },
282
+ metadata: { executionTimeMs: Date.now() - startedAt },
283
+ });
284
+
285
+ return emit(env);
286
+ }
287
+
288
+ if (require.main === module) {
289
+ process.exit(runOrSkip('batch', main));
290
+ }
291
+
292
+ module.exports = { dispatch, validateStep, validateAllSteps, VALID_ACTIONS };