@proagentstore/cli 0.4.147 → 0.4.149
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.
|
@@ -610,6 +610,18 @@ export class ApplyBridge {
|
|
|
610
610
|
this.host.emit({ type: "browser.blocked", url: state.url, domain: host, detail: { reason: "login_required" } });
|
|
611
611
|
this.blocked = { reason: "login_required", questions: [signInQuestion(siteKeyOf(host))] };
|
|
612
612
|
}
|
|
613
|
+
// Nothing entered, no sign-in, no other blocker (#1133): the run never found a form it could fill — a
|
|
614
|
+
// layout it did not recognise, a form that never opened. That is a failure to fill, recorded with its
|
|
615
|
+
// reason, never `review.ready` count 0: an owner reading "awaiting review" is told a form is waiting,
|
|
616
|
+
// and a retry repeats the same silent no-op.
|
|
617
|
+
else if (!this.filled && !this.uploaded.size && !this.blocked) {
|
|
618
|
+
this.blocked = {
|
|
619
|
+
reason: "incomplete",
|
|
620
|
+
questions: [
|
|
621
|
+
`The run ended without entering anything on this application${state?.url ? ` (it stopped at ${hostOf(state.url) ?? "the site"})` : ""} — it found no form it could fill, or the form never opened. Nothing was submitted. Open the application yourself, or retry once the page shows its form.`,
|
|
622
|
+
],
|
|
623
|
+
};
|
|
624
|
+
}
|
|
613
625
|
// #989: "ready for review" with nothing entered is not a review state.
|
|
614
626
|
//
|
|
615
627
|
// The live run ended `awaiting_review` with `filled: 0, uploaded: 0` seconds after the cloud
|
|
@@ -48,6 +48,12 @@ const SAFE_ID = /^[A-Za-z0-9_.:-]{1,300}$/;
|
|
|
48
48
|
const HASH = /^[a-f0-9]{64}$/;
|
|
49
49
|
/** One application at a time per agent: two runs on one employer's form is how duplicates happen. */
|
|
50
50
|
const MAX_ACTIVE = 1;
|
|
51
|
+
/**
|
|
52
|
+
* Pauses that wait on a DECISION, not on the page (#1121): the owner's stored answer satisfies them on
|
|
53
|
+
* a fresh fill, so a run paused on one gives the machine back. Every other pause — sign-in, CAPTCHA,
|
|
54
|
+
* consent, a redirect, the supervisor's checkpoint — needs this exact live page and keeps it.
|
|
55
|
+
*/
|
|
56
|
+
const PARKABLE_PAUSES = new Set(["missing_answer", "screening_ambiguity"]);
|
|
51
57
|
class Blocked extends Error {
|
|
52
58
|
reason;
|
|
53
59
|
questions;
|
|
@@ -554,6 +560,21 @@ export class LocalApplyRuntime {
|
|
|
554
560
|
pause(run, p) {
|
|
555
561
|
if (run.state === "ended" || run.cancelled)
|
|
556
562
|
return Promise.resolve("stopped");
|
|
563
|
+
// #1121: a question only the owner can answer does not need this page — park it. The run ENDS
|
|
564
|
+
// `blocked` with the question, the browser and the CLI stop, and the machine's one slot is free
|
|
565
|
+
// for the next application. The owner's answer is stored (#1079) and re-fills this application
|
|
566
|
+
// from a fresh page, with the answer as a source. Never once a submit was attempted: that run
|
|
567
|
+
// must not be filled again (#1013, #1073), so it keeps holding the slot and its page.
|
|
568
|
+
if (run.state === "running" && PARKABLE_PAUSES.has(p.reason) && !run.bridge?.submitAttempted) {
|
|
569
|
+
this.emit(run, { type: "run.paused", pauseReason: p.reason });
|
|
570
|
+
this.end(run, {
|
|
571
|
+
outcome: "blocked",
|
|
572
|
+
blockReason: p.reason,
|
|
573
|
+
questions: p.question ? [p.question] : [],
|
|
574
|
+
summary: "Parked for the owner's answer; this machine was freed. Nothing was submitted.",
|
|
575
|
+
});
|
|
576
|
+
return Promise.resolve("stopped");
|
|
577
|
+
}
|
|
557
578
|
if (run.state === "running") {
|
|
558
579
|
run.activeMs += this.now() - run.activeSince;
|
|
559
580
|
run.state = "paused";
|