blastproof 0.17.0 → 0.18.0

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/dist/cli.js CHANGED
@@ -598,6 +598,23 @@ var StepRecovery = class {
598
598
  observe(maskedSnapshot) {
599
599
  this.readable.push(normalise(maskedSnapshot));
600
600
  }
601
+ /**
602
+ * Whether anything succeeded during this step (design close-a-step D1).
603
+ *
604
+ * Reads the history `record` already keeps rather than a flag threaded
605
+ * through the loop: `record` is reached at one place, after `performAction`
606
+ * returns without throwing, so this is "what worked" and not "what was
607
+ * attempted" — a click that raised is correctly absent. A separate counter
608
+ * would be one more thing a future branch can forget to increment, which is
609
+ * the shape that let `timeoutMs` and the budget go unset at a single call
610
+ * site while every other one set them.
611
+ *
612
+ * `observe` deliberately does not move it. Being shown a page is not doing
613
+ * something to it.
614
+ */
615
+ get acted() {
616
+ return this.history.length > 0;
617
+ }
601
618
  /** Records an action that was actually performed and succeeded. */
602
619
  record(action, description, result) {
603
620
  this.performed.add(identity(action));
@@ -691,6 +708,7 @@ function slugify(text) {
691
708
  const slug = text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
692
709
  return slug || "test";
693
710
  }
711
+ var NOTHING_DONE_REFUSAL = "refused: nothing succeeded during this step, so it was NOT closed. A step closes on what was done in it, not on being declared finished. If the outcome already holds \u2014 there was nothing left to do \u2014 assert that it holds and let the judgment close the step; an assertion is evidence, a declaration is not. If the step cannot be carried out at all, fail it and say why.";
694
712
  var StepFailure = class extends Error {
695
713
  };
696
714
  async function executeTest(page, test, options) {
@@ -775,6 +793,15 @@ async function executeTest(page, test, options) {
775
793
  }
776
794
  iterations++;
777
795
  if (action.action === "done") {
796
+ if (!recovery.acted) {
797
+ failedAttempts++;
798
+ lastResult = NOTHING_DONE_REFUSAL;
799
+ emitAction(index, action, lastResult);
800
+ if (failedAttempts >= maxRetries) {
801
+ throw new StepFailure(lastResult);
802
+ }
803
+ continue;
804
+ }
778
805
  emitAction(index, action, action.reasoning);
779
806
  break;
780
807
  }
@@ -3082,7 +3109,7 @@ function parsePositiveNumber(flag) {
3082
3109
  };
3083
3110
  }
3084
3111
  var program = new Command();
3085
- program.name("blastproof").description("Open-source AI testing agent: plain-English YAML tests executed agentically on a real browser.").version("0.17.0");
3112
+ program.name("blastproof").description("Open-source AI testing agent: plain-English YAML tests executed agentically on a real browser.").version("0.18.0");
3086
3113
  program.command("init").description("Scaffold .blastproof/ (config, tests, sample tests) in the current directory").action(async () => {
3087
3114
  try {
3088
3115
  const result = await initProject(process.cwd());