@proagentstore/cli 0.4.2 → 0.4.3

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.
@@ -680,6 +680,45 @@ export class LocalRunner {
680
680
  const head = (cut >= 0 ? text.slice(0, cut) : text).replace(/```[a-z]*\n?|```/g, " ").replace(/\s+/g, " ").trim();
681
681
  return head.slice(0, 400);
682
682
  }
683
+ /**
684
+ * After a WRITE action, read the field's REAL value back via the standard
685
+ * browser_evaluate tool (evaluates on the element by ref — no reinvented DOM
686
+ * traversal). Masked/intl fields transform input (e.g. "0404453580" → "+61404453580"),
687
+ * so without this signal the brain can't tell the value "took" and oscillates
688
+ * between formats. Returns the prompt's expected "…now reads…" / "REJECTED…" line.
689
+ * Never throws — best-effort feedback.
690
+ */
691
+ async readBackField(mcp, action) {
692
+ if (!action.ref)
693
+ return "";
694
+ const fn = "el => ({ v: el.value !== undefined ? String(el.value) : (el.getAttribute('aria-checked') ?? el.textContent ?? '').trim(), " +
695
+ "bad: el.getAttribute('aria-invalid') === 'true' || !!(el.validity && !el.validity.valid), " +
696
+ "msg: el.validationMessage || '' })";
697
+ const res = await mcp.callTool("browser_evaluate", { element: action.name || "field", target: action.ref, function: fn }).catch(() => null);
698
+ if (!res || res.isError)
699
+ return "";
700
+ const txt = mcp.textOf(res);
701
+ const i = txt.indexOf("### Result");
702
+ if (i < 0)
703
+ return "";
704
+ const after = txt.slice(i + "### Result".length).trim();
705
+ const end = after.indexOf("\n###");
706
+ const block = (end >= 0 ? after.slice(0, end) : after).trim();
707
+ let parsed;
708
+ try {
709
+ parsed = JSON.parse(block);
710
+ }
711
+ catch {
712
+ return "";
713
+ }
714
+ if (typeof parsed?.v !== "string")
715
+ return "";
716
+ const name = action.name || "field";
717
+ const shown = parsed.v.length > 80 ? `${parsed.v.slice(0, 80)}…` : parsed.v;
718
+ if (parsed.bad)
719
+ return `⚠ "${name}" REJECTED: now reads "${shown}"${parsed.msg ? ` — ${parsed.msg.slice(0, 80)}` : ""}`;
720
+ return `"${name}" now reads "${shown}"`;
721
+ }
683
722
  /** The snapshot ref the brain must target the element by (standard-tool `target`). */
684
723
  refOf(action) {
685
724
  const ref = (action.ref || "").trim();
@@ -817,12 +856,21 @@ export class LocalRunner {
817
856
  if (action.action === "click" || action.action === "navigate" || action.action === "key") {
818
857
  await active.waitForLoadState("networkidle", { timeout: 3_500 }).catch(() => undefined);
819
858
  }
859
+ // For a WRITE, read the field's real value back (masked/intl fields transform
860
+ // input, e.g. "0404453580" → "+61404453580") so the brain knows it took and
861
+ // stops oscillating between formats — the signal inspectField used to give.
862
+ let feedback = this.conciseFeedback(text);
863
+ if (action.action === "type" || action.action === "select" || action.action === "check") {
864
+ const rb = await this.readBackField(mcp, action);
865
+ if (rb)
866
+ feedback = rb;
867
+ }
820
868
  return {
821
869
  ok: true,
822
870
  url: active.url(),
823
871
  title: await active.title().catch(() => ""),
824
872
  challenge: await detectHumanChallenge(active),
825
- feedback: this.conciseFeedback(text) || undefined,
873
+ feedback: feedback || undefined,
826
874
  };
827
875
  }
828
876
  // ── Agent-driven application lifecycle (called by the remote Workflow brain) ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",