@proagentstore/cli 0.4.135 → 0.4.137
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.
|
@@ -225,7 +225,8 @@ export class LocalApplyRuntime {
|
|
|
225
225
|
return { state: "unavailable", jobUrl: parsed.toString(), reason: gone };
|
|
226
226
|
// An accessible Apply control is an active path, unlike a generic careers/search URL.
|
|
227
227
|
if (/(?:button|link)\s+"[^"]{0,80}\bapply(?: now| for| here)?\b|\bapply (?:now|for (?:this )?(?:job|role|position))\b|\bstart application\b/i.test(page)) {
|
|
228
|
-
|
|
228
|
+
const title = page.match(/^\s*-?\s*Page Title:\s*(.+)$/m)?.[1]?.trim().slice(0, 300); // names a posting pasted with none (#1098)
|
|
229
|
+
return { state: "live", jobUrl: parsed.toString(), applyUrl: parsed.toString(), evidence: "apply_control_present", ...(title ? { title } : {}) };
|
|
229
230
|
}
|
|
230
231
|
return { state: "unverifiable", jobUrl: parsed.toString(), reason: "no_active_apply_path" };
|
|
231
232
|
}
|
|
@@ -10,6 +10,7 @@ import { isTerminalTaskStatus, settleTaskOutcome } from "./apply-outcome.js";
|
|
|
10
10
|
import { McpRuntime } from "./mcp-runtime.js";
|
|
11
11
|
import { commitLabelRe, ELEMENT_PROBE_FN, FOCUS_PROBE_FN, refuseClick, refuseKey } from "./commit-guard.js";
|
|
12
12
|
import { HumanHandoffError, RunnerInputError } from "./errors.js";
|
|
13
|
+
import { takeoverNavigation } from "./takeover-nav.js";
|
|
13
14
|
import { resolveHandoffStatus } from "./handoff-status.js";
|
|
14
15
|
import { RunnerStore } from "./store.js";
|
|
15
16
|
import { CodingRuntime } from "./coding/runtime.js";
|
|
@@ -477,6 +478,7 @@ export class LocalRunner {
|
|
|
477
478
|
frame: `data:image/jpeg;base64,${session.latestFrame ?? ""}`,
|
|
478
479
|
width: session.cssW ?? session.width ?? 1280,
|
|
479
480
|
height: session.cssH ?? session.height ?? 720,
|
|
481
|
+
url: session.page.url(), // the live view's address bar (#1105)
|
|
480
482
|
};
|
|
481
483
|
}
|
|
482
484
|
/** Relay a human's mouse/keyboard input into the real page via CDP. */
|
|
@@ -488,6 +490,8 @@ export class LocalRunner {
|
|
|
488
490
|
const cdp = session.cdp;
|
|
489
491
|
const x = input.x ?? 0;
|
|
490
492
|
const y = input.y ?? 0;
|
|
493
|
+
if (await takeoverNavigation(session.page, input))
|
|
494
|
+
return; // back/forward/reload/address bar (#1105)
|
|
491
495
|
switch (input.type) {
|
|
492
496
|
case "move":
|
|
493
497
|
await cdp.send("Input.dispatchMouseEvent", { type: "mouseMoved", x, y });
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { RunnerInputError } from "./errors.js";
|
|
2
|
+
/** A slow page still lands where it was sent and the frame poll shows it, so a timeout is not a failure. */
|
|
3
|
+
const NAV = { waitUntil: "commit", timeout: 15_000 };
|
|
4
|
+
/** Run a navigation control. True when `input` was one (and was handled); false for every other input. */
|
|
5
|
+
export async function takeoverNavigation(page, input) {
|
|
6
|
+
if (input.type === "back")
|
|
7
|
+
await page.goBack(NAV).catch(() => undefined);
|
|
8
|
+
else if (input.type === "forward")
|
|
9
|
+
await page.goForward(NAV).catch(() => undefined);
|
|
10
|
+
else if (input.type === "reload")
|
|
11
|
+
await page.reload(NAV).catch(() => undefined);
|
|
12
|
+
else if (input.type === "navigate") {
|
|
13
|
+
const url = takeoverUrl(input.url);
|
|
14
|
+
if (!url)
|
|
15
|
+
throw new RunnerInputError("navigate takes an http(s) address");
|
|
16
|
+
await page.goto(url, NAV).catch(() => undefined);
|
|
17
|
+
}
|
|
18
|
+
else
|
|
19
|
+
return false;
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* What the address bar may open: an http(s) address, as an address bar takes it — a bare host gets
|
|
24
|
+
* `https://`. Anything else (`file:`, `javascript:`, `chrome:`) is refused.
|
|
25
|
+
*/
|
|
26
|
+
export function takeoverUrl(raw) {
|
|
27
|
+
const text = typeof raw === "string" ? raw.trim() : "";
|
|
28
|
+
if (!text || /\s/.test(text))
|
|
29
|
+
return null;
|
|
30
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:/i.test(text) ? text : `https://${text}`;
|
|
31
|
+
try {
|
|
32
|
+
const u = new URL(withScheme);
|
|
33
|
+
return u.protocol === "http:" || u.protocol === "https:" ? u.toString() : null;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|