@proagentstore/cli 0.3.3 → 0.3.4
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.
|
@@ -194,3 +194,69 @@ export async function performBrowserAction(page, action, clickRobustly, resumeFi
|
|
|
194
194
|
}
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
+
/**
|
|
198
|
+
* After a WRITE action (type/select/check), read back what the field actually
|
|
199
|
+
* holds now + any validation error rendered near it. This is the semantic
|
|
200
|
+
* feedback the brain otherwise lacks: `fill()` succeeding doesn't mean the value
|
|
201
|
+
* "took" (masked/intl widgets concatenate; validators reject a format). Returns a
|
|
202
|
+
* short human string for the action log, or "" when there's nothing notable.
|
|
203
|
+
* Never throws.
|
|
204
|
+
*/
|
|
205
|
+
export async function inspectField(page, action) {
|
|
206
|
+
if (action.action !== "type" && action.action !== "select" && action.action !== "check")
|
|
207
|
+
return "";
|
|
208
|
+
if (!action.name)
|
|
209
|
+
return "";
|
|
210
|
+
try {
|
|
211
|
+
const role = action.role;
|
|
212
|
+
let loc = role ? page.getByRole(role, { name: action.name }) : page.getByText(action.name, { exact: false });
|
|
213
|
+
loc = typeof action.nth === "number" ? loc.nth(action.nth) : loc.first();
|
|
214
|
+
const el = await loc.elementHandle({ timeout: 1_500 }).catch(() => null);
|
|
215
|
+
if (!el)
|
|
216
|
+
return "";
|
|
217
|
+
const info = await el
|
|
218
|
+
.evaluate((node) => {
|
|
219
|
+
const e = node;
|
|
220
|
+
const raw = typeof e.value === "string" ? e.value : (e.getAttribute("aria-checked") ?? e.textContent ?? "");
|
|
221
|
+
const value = String(raw).trim().slice(0, 120);
|
|
222
|
+
const invalid = e.getAttribute("aria-invalid") === "true" || (typeof e.matches === "function" && e.matches(":invalid"));
|
|
223
|
+
let err = "";
|
|
224
|
+
const rx = /invalid|required|must|valid|error|format|enter a|please/i;
|
|
225
|
+
const describedby = e.getAttribute("aria-describedby");
|
|
226
|
+
if (describedby) {
|
|
227
|
+
for (const id of describedby.split(/\s+/)) {
|
|
228
|
+
const d = document.getElementById(id);
|
|
229
|
+
const t = (d?.textContent || "").trim();
|
|
230
|
+
if (t && rx.test(t)) {
|
|
231
|
+
err = t;
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (!err) {
|
|
237
|
+
const scope = e.closest("[class*=field], [class*=form-group], [class*=form-item], fieldset") || e.parentElement;
|
|
238
|
+
const cand = scope?.querySelector('[role="alert"], [class*=error i], [class*=invalid i], [class*=danger i], [class*=help-block i]');
|
|
239
|
+
const t = (cand?.textContent || "").trim();
|
|
240
|
+
if (t && rx.test(t) && t.length < 180)
|
|
241
|
+
err = t;
|
|
242
|
+
}
|
|
243
|
+
return { value, invalid, err: err.replace(/\s+/g, " ").slice(0, 180) };
|
|
244
|
+
})
|
|
245
|
+
.catch(() => null);
|
|
246
|
+
if (!info)
|
|
247
|
+
return "";
|
|
248
|
+
const typed = String(action.text ?? "").trim();
|
|
249
|
+
const parts = [];
|
|
250
|
+
if (info.err)
|
|
251
|
+
parts.push(`⚠ "${action.name}" REJECTED: "${info.err}"`);
|
|
252
|
+
if (info.value && (info.invalid || info.err || (typed && info.value !== typed))) {
|
|
253
|
+
parts.push(`"${action.name}" now reads "${info.value}"${typed && info.value !== typed ? ` (you sent "${typed}")` : ""}`);
|
|
254
|
+
}
|
|
255
|
+
if (info.invalid && !info.err)
|
|
256
|
+
parts.push(`"${action.name}" is marked invalid`);
|
|
257
|
+
return parts.join("; ");
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
return "";
|
|
261
|
+
}
|
|
262
|
+
}
|
|
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from "node:path";
|
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
6
|
import { captureScreenshotDataUrl, challengeSolved, detectHumanChallenge } from "./challenge.js";
|
|
7
7
|
import { resolveRealChromeProfileDir, seedProfileCopy } from "./browser-profile.js";
|
|
8
|
-
import { performBrowserAction } from "./browser-actions.js";
|
|
8
|
+
import { inspectField, performBrowserAction } from "./browser-actions.js";
|
|
9
9
|
import { HumanHandoffError, RunnerInputError } from "./errors.js";
|
|
10
10
|
import { RunnerStore } from "./store.js";
|
|
11
11
|
import { CodingRuntime } from "./coding/runtime.js";
|
|
@@ -664,11 +664,15 @@ export class LocalRunner {
|
|
|
664
664
|
if (action.action === "click" || action.action === "navigate" || action.action === "key") {
|
|
665
665
|
await active.waitForLoadState("networkidle", { timeout: 3_500 }).catch(() => undefined);
|
|
666
666
|
}
|
|
667
|
+
// Read back what a write action actually did (real field value + any validation
|
|
668
|
+
// error) so the brain gets semantic feedback, not just "Playwright didn't throw".
|
|
669
|
+
const feedback = await inspectField(active, action).catch(() => "");
|
|
667
670
|
return {
|
|
668
671
|
ok: true,
|
|
669
672
|
url: active.url(),
|
|
670
673
|
title: await active.title().catch(() => ""),
|
|
671
674
|
challenge: await detectHumanChallenge(active),
|
|
675
|
+
feedback: feedback || undefined,
|
|
672
676
|
};
|
|
673
677
|
}
|
|
674
678
|
/**
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
2
|
+
"name": "@proagentstore/cli",
|
|
3
|
+
"version": "0.3.4",
|
|
4
|
+
"description": "CLI for creating, publishing, and running ProAgentStore agents",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pags": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/ProAgentStore/platform#readme",
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "git+https://github.com/ProAgentStore/platform.git",
|
|
14
|
+
"directory": "packages/cli"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"proagentstore",
|
|
18
|
+
"pags",
|
|
19
|
+
"cli",
|
|
20
|
+
"agents",
|
|
21
|
+
"mcp",
|
|
22
|
+
"browser-runner"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "pnpm --filter @proagentstore/browser-runner build && tsup src/index.ts --format esm --dts && node scripts/copy-browser-runner.mjs",
|
|
29
|
+
"dev": "tsx src/index.ts",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"chalk": "^5.6.2",
|
|
34
|
+
"commander": "^13.0.0",
|
|
35
|
+
"playwright": "^1.60.0"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/node": "^22.0.0",
|
|
39
|
+
"tsup": "^8.4.0",
|
|
40
|
+
"tsx": "^4.21.0",
|
|
41
|
+
"typescript": "^5.7.0"
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist"
|
|
45
|
+
]
|
|
46
46
|
}
|