@enricai/barnacle 1.12.71 → 1.12.73
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/recon/capture-filters.d.ts +8 -1
- package/dist/recon/capture-filters.d.ts.map +1 -1
- package/dist/recon/capture-filters.js +97 -26
- package/dist/recon/capture-filters.js.map +1 -1
- package/dist/scraper/flow-runner.d.ts +61 -0
- package/dist/scraper/flow-runner.d.ts.map +1 -1
- package/dist/scraper/flow-runner.js +138 -46
- package/dist/scraper/flow-runner.js.map +1 -1
- package/dist/scraper/submit-control.d.ts +23 -1
- package/dist/scraper/submit-control.d.ts.map +1 -1
- package/dist/scraper/submit-control.js +40 -3
- package/dist/scraper/submit-control.js.map +1 -1
- package/dist/scripts/recon-browser.d.ts +10 -2
- package/dist/scripts/recon-browser.d.ts.map +1 -1
- package/dist/scripts/recon-browser.js +93 -27
- package/dist/scripts/recon-browser.js.map +1 -1
- package/dist/scripts/recon-generate.d.ts +148 -6
- package/dist/scripts/recon-generate.d.ts.map +1 -1
- package/dist/scripts/recon-generate.js +557 -80
- package/dist/scripts/recon-generate.js.map +1 -1
- package/package.json +1 -1
|
@@ -35,7 +35,29 @@ export declare const NEGATIVE_TEXT_EXPR = "((text) => {\n const negatives = [\"
|
|
|
35
35
|
* accept any div/input regardless of text, exactly the "arbitrary structural
|
|
36
36
|
* divs" false-positive this module's docblock warns against.
|
|
37
37
|
*/
|
|
38
|
-
export declare const SUBMIT_SHAPE_FALLBACK_EXPR = "((el, name, isNegative) => {\n if (/\\b(create|continue|next|confirm|proceed)\\b/.test(name)) return true;\n if (name !== \"\") return false;\n const isFormLike = (node) =>\n (node.tagName || \"\").toLowerCase() === \"form\" ||\n (node.getAttribute && (node.getAttribute(\"role\") || \"\").toLowerCase() === \"form\");\n const findFormContainer = (node) => {\n for (let depth = 0; depth < 6 && node; depth++) {\n if (isFormLike(node)) return node;\n node = node.parentElement;\n }\n return null;\n };\n const container = findFormContainer(el.parentElement);\n if (!container) return false;\n const accessibleName = ((el) => {\n const norm = (s) => (s || \"\").replace(/\\s+/g, \" \").trim().toLowerCase();\n return norm(el.getAttribute(\"aria-label\") ||
|
|
38
|
+
export declare const SUBMIT_SHAPE_FALLBACK_EXPR = "((el, name, isNegative) => {\n if (/\\b(create|continue|next|confirm|proceed)\\b/.test(name)) return true;\n if (name !== \"\") return false;\n const isFormLike = (node) =>\n (node.tagName || \"\").toLowerCase() === \"form\" ||\n (node.getAttribute && (node.getAttribute(\"role\") || \"\").toLowerCase() === \"form\");\n const findFormContainer = (node) => {\n for (let depth = 0; depth < 6 && node; depth++) {\n if (isFormLike(node)) return node;\n node = node.parentElement;\n }\n return null;\n };\n const container = findFormContainer(el.parentElement);\n if (!container) return false;\n const accessibleName = ((el) => {\n const norm = (s) => (s || \"\").replace(/\\s+/g, \" \").trim().toLowerCase();\n const tag = (el.tagName || \"\").toLowerCase();\n const fallback = tag === \"input\" ? el.value : el.textContent;\n return norm(el.getAttribute(\"aria-label\") || fallback || \"\");\n});\n const isCandidate = (c) => {\n if (c === el) return true;\n const cTag = (c.tagName || \"\").toLowerCase();\n const cRole = (c.getAttribute(\"role\") || \"\").toLowerCase();\n if (cTag !== \"button\" && cTag !== \"input\" && cRole !== \"button\") return false;\n return !isNegative(accessibleName(c));\n };\n const candidates = Array.from(container.querySelectorAll(\"*\")).filter(isCandidate);\n return candidates.length === 1 && candidates[0] === el;\n})";
|
|
39
|
+
/**
|
|
40
|
+
* Single site-agnostic submit-shape predicate: `(el) => boolean`, composing
|
|
41
|
+
* {@link NEGATIVE_TEXT_EXPR}, {@link ACCESSIBLE_NAME_EXPR}, and
|
|
42
|
+
* {@link SUBMIT_SHAPE_FALLBACK_EXPR} so every caller shares one decision
|
|
43
|
+
* boundary instead of hand-rolling a divergent copy. No tag or `type`
|
|
44
|
+
* attribute — not even `<input type="submit">`/`type="image">`, nor an
|
|
45
|
+
* explicit `type="submit"` on a `<button>`/`<input>` — earns unconditional
|
|
46
|
+
* structural credit: a native submit-typed control that click-intercepts
|
|
47
|
+
* rather than actually submitting (e.g. a "Show contact form" reveal toggle
|
|
48
|
+
* a page happens to mark up as `<button type="submit">` for layout reasons,
|
|
49
|
+
* with no submit intent at all) must earn its credit through the SAME
|
|
50
|
+
* corroboration path as a non-native `<div>`/`<a>`/custom-element action
|
|
51
|
+
* control — {@link SUBMIT_SHAPE_FALLBACK_EXPR}'s generic-action-verb
|
|
52
|
+
* accessible name, or sole-actionable-candidate-in-form when it carries no
|
|
53
|
+
* text. Exported so `flow-runner.ts`'s `resolvedClickTargetIsSubmitShaped` /
|
|
54
|
+
* `XPATH_TAIL_RETARGET_RESOLVE_FN_SRC` share this one boolean producer
|
|
55
|
+
* instead of re-diverging. {@link RANK_TIERS_EXPR} independently retains the
|
|
56
|
+
* unconditional explicit-`type="submit"` credit for its own graduated (not
|
|
57
|
+
* boolean) tiering — a separate producer used for candidate
|
|
58
|
+
* ranking/disambiguation, not this verification veto.
|
|
59
|
+
*/
|
|
60
|
+
export declare const SUBMIT_SHAPE_EXPR = "((el) => {\n if (!el || !el.tagName) return false;\n const isNegative = ((text) => {\n const negatives = [\"back\", \"cancel\", \"save draft\", \"save for later\", \"previous\", \"close\"];\n return negatives.some((n) => text === n || text.startsWith(n + \" \") || text.endsWith(\" \" + n));\n});\n const accessibleName = ((el) => {\n const norm = (s) => (s || \"\").replace(/\\s+/g, \" \").trim().toLowerCase();\n const tag = (el.tagName || \"\").toLowerCase();\n const fallback = tag === \"input\" ? el.value : el.textContent;\n return norm(el.getAttribute(\"aria-label\") || fallback || \"\");\n});\n const name = accessibleName(el);\n if (isNegative(name)) return false;\n const isFallbackShaped = ((el, name, isNegative) => {\n if (/\\b(create|continue|next|confirm|proceed)\\b/.test(name)) return true;\n if (name !== \"\") return false;\n const isFormLike = (node) =>\n (node.tagName || \"\").toLowerCase() === \"form\" ||\n (node.getAttribute && (node.getAttribute(\"role\") || \"\").toLowerCase() === \"form\");\n const findFormContainer = (node) => {\n for (let depth = 0; depth < 6 && node; depth++) {\n if (isFormLike(node)) return node;\n node = node.parentElement;\n }\n return null;\n };\n const container = findFormContainer(el.parentElement);\n if (!container) return false;\n const accessibleName = ((el) => {\n const norm = (s) => (s || \"\").replace(/\\s+/g, \" \").trim().toLowerCase();\n const tag = (el.tagName || \"\").toLowerCase();\n const fallback = tag === \"input\" ? el.value : el.textContent;\n return norm(el.getAttribute(\"aria-label\") || fallback || \"\");\n});\n const isCandidate = (c) => {\n if (c === el) return true;\n const cTag = (c.tagName || \"\").toLowerCase();\n const cRole = (c.getAttribute(\"role\") || \"\").toLowerCase();\n if (cTag !== \"button\" && cTag !== \"input\" && cRole !== \"button\") return false;\n return !isNegative(accessibleName(c));\n };\n const candidates = Array.from(container.querySelectorAll(\"*\")).filter(isCandidate);\n return candidates.length === 1 && candidates[0] === el;\n});\n return isFallbackShaped(el, name, isNegative);\n})";
|
|
39
61
|
/**
|
|
40
62
|
* Builds a self-contained `page.evaluate` expression string that walks the
|
|
41
63
|
* whole document (light DOM plus every open shadow root, arbitrarily deep)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit-control.d.ts","sourceRoot":"","sources":["../../src/scraper/submit-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,sOAG5B,CAAC;
|
|
1
|
+
{"version":3,"file":"submit-control.d.ts","sourceRoot":"","sources":["../../src/scraper/submit-control.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,sOAG5B,CAAC;AA8EJ;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,0BAA0B,s4CAyBpC,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,uoEAQ3B,CAAC;AA+CJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,SAAa,GAAG,MAAM,CA0BvE;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,SAAa,GAAG,MAAM,CAYtF;AAED,2HAA2H;AAC3H,MAAM,MAAM,mBAAmB,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAElD,qGAAqG;AACrG,MAAM,WAAW,eAAe;IAC9B,mIAAmI;IACnI,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,oKAAoK;IACpK,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B"}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* included, and "Back"/"Cancel"/"Save draft"-shaped controls never appear.
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.SUBMIT_SHAPE_FALLBACK_EXPR = exports.NEGATIVE_TEXT_EXPR = void 0;
|
|
13
|
+
exports.SUBMIT_SHAPE_EXPR = exports.SUBMIT_SHAPE_FALLBACK_EXPR = exports.NEGATIVE_TEXT_EXPR = void 0;
|
|
14
14
|
exports.buildRankSubmitCandidatesExpr = buildRankSubmitCandidatesExpr;
|
|
15
15
|
exports.buildClickByDeepIndexExpr = buildClickByDeepIndexExpr;
|
|
16
16
|
const browser_click_expr_1 = require("./browser-click-expr");
|
|
@@ -30,11 +30,18 @@ exports.NEGATIVE_TEXT_EXPR = `((text) => {
|
|
|
30
30
|
})`;
|
|
31
31
|
/**
|
|
32
32
|
* Normalizes an element's accessible name to lowercase, whitespace-collapsed
|
|
33
|
-
* text, preferring `aria-label` over visible `textContent
|
|
33
|
+
* text, preferring `aria-label` over visible `textContent`, falling back to
|
|
34
|
+
* `value` for an `<input>` (which never has text-node children, so its
|
|
35
|
+
* accessible name comes from its `value` attribute per native AccName
|
|
36
|
+
* semantics — without this, an `<input type="submit" value="Create
|
|
37
|
+
* Account">` normalizes to an empty name and cannot earn corroboration
|
|
38
|
+
* through {@link SUBMIT_SHAPE_FALLBACK_EXPR}'s generic-action-verb check).
|
|
34
39
|
*/
|
|
35
40
|
const ACCESSIBLE_NAME_EXPR = `((el) => {
|
|
36
41
|
const norm = (s) => (s || "").replace(/\\s+/g, " ").trim().toLowerCase();
|
|
37
|
-
|
|
42
|
+
const tag = (el.tagName || "").toLowerCase();
|
|
43
|
+
const fallback = tag === "input" ? el.value : el.textContent;
|
|
44
|
+
return norm(el.getAttribute("aria-label") || fallback || "");
|
|
38
45
|
})`;
|
|
39
46
|
/**
|
|
40
47
|
* Visibility check: a node with a 0x0 layout box, or a computed
|
|
@@ -135,6 +142,36 @@ exports.SUBMIT_SHAPE_FALLBACK_EXPR = `((el, name, isNegative) => {
|
|
|
135
142
|
const candidates = Array.from(container.querySelectorAll("*")).filter(isCandidate);
|
|
136
143
|
return candidates.length === 1 && candidates[0] === el;
|
|
137
144
|
})`;
|
|
145
|
+
/**
|
|
146
|
+
* Single site-agnostic submit-shape predicate: `(el) => boolean`, composing
|
|
147
|
+
* {@link NEGATIVE_TEXT_EXPR}, {@link ACCESSIBLE_NAME_EXPR}, and
|
|
148
|
+
* {@link SUBMIT_SHAPE_FALLBACK_EXPR} so every caller shares one decision
|
|
149
|
+
* boundary instead of hand-rolling a divergent copy. No tag or `type`
|
|
150
|
+
* attribute — not even `<input type="submit">`/`type="image">`, nor an
|
|
151
|
+
* explicit `type="submit"` on a `<button>`/`<input>` — earns unconditional
|
|
152
|
+
* structural credit: a native submit-typed control that click-intercepts
|
|
153
|
+
* rather than actually submitting (e.g. a "Show contact form" reveal toggle
|
|
154
|
+
* a page happens to mark up as `<button type="submit">` for layout reasons,
|
|
155
|
+
* with no submit intent at all) must earn its credit through the SAME
|
|
156
|
+
* corroboration path as a non-native `<div>`/`<a>`/custom-element action
|
|
157
|
+
* control — {@link SUBMIT_SHAPE_FALLBACK_EXPR}'s generic-action-verb
|
|
158
|
+
* accessible name, or sole-actionable-candidate-in-form when it carries no
|
|
159
|
+
* text. Exported so `flow-runner.ts`'s `resolvedClickTargetIsSubmitShaped` /
|
|
160
|
+
* `XPATH_TAIL_RETARGET_RESOLVE_FN_SRC` share this one boolean producer
|
|
161
|
+
* instead of re-diverging. {@link RANK_TIERS_EXPR} independently retains the
|
|
162
|
+
* unconditional explicit-`type="submit"` credit for its own graduated (not
|
|
163
|
+
* boolean) tiering — a separate producer used for candidate
|
|
164
|
+
* ranking/disambiguation, not this verification veto.
|
|
165
|
+
*/
|
|
166
|
+
exports.SUBMIT_SHAPE_EXPR = `((el) => {
|
|
167
|
+
if (!el || !el.tagName) return false;
|
|
168
|
+
const isNegative = ${exports.NEGATIVE_TEXT_EXPR};
|
|
169
|
+
const accessibleName = ${ACCESSIBLE_NAME_EXPR};
|
|
170
|
+
const name = accessibleName(el);
|
|
171
|
+
if (isNegative(name)) return false;
|
|
172
|
+
const isFallbackShaped = ${exports.SUBMIT_SHAPE_FALLBACK_EXPR};
|
|
173
|
+
return isFallbackShaped(el, name, isNegative);
|
|
174
|
+
})`;
|
|
138
175
|
/**
|
|
139
176
|
* Ranking tiers, most confident first. Each tier's `test` receives the
|
|
140
177
|
* element plus its precomputed accessible name and reports whether it
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit-control.js","sourceRoot":"","sources":["../../src/scraper/submit-control.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;AAEH,qEAAiG;AAEjG;;;;;;;;;GASG;AACU,QAAA,kBAAkB,GAAG;;;GAG/B,CAAC;AAEJ
|
|
1
|
+
{"version":3,"file":"submit-control.js","sourceRoot":"","sources":["../../src/scraper/submit-control.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;AAEH,qEAAiG;AAEjG;;;;;;;;;GASG;AACU,QAAA,kBAAkB,GAAG;;;GAG/B,CAAC;AAEJ;;;;;;;;GAQG;AACH,MAAM,oBAAoB,GAAG;;;;;GAK1B,CAAC;AAEJ;;;;;;;;;;GAUG;AACH,MAAM,eAAe,GAAG;;;;;GAKrB,CAAC;AAEJ;;;;;;;;;;;;;;GAcG;AACH,MAAM,gBAAgB,GAAG;gCACO,iDAA4B;;;;;;GAMzD,CAAC;AAEJ;;;;GAIG;AACH,MAAM,kBAAkB,GAAG;;;;;;;;;;;GAWxB,CAAC;AAEJ;;;;;;;;;;;;;;;GAeG;AACU,QAAA,0BAA0B,GAAG;;;;;;;kCAOR,iDAA4B;;;;;;;;2BAQnC,oBAAoB;;;;;;;;;;GAU5C,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;GAoBG;AACU,QAAA,iBAAiB,GAAG;;uBAEV,QAAA,kBAAkB;2BACd,oBAAoB;;;6BAGlB,QAAA,0BAA0B;;GAEpD,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,eAAe,GAAG;uBACD,QAAA,kBAAkB;;;;;;;;;;6BAUZ,QAAA,0BAA0B;;;GAGpD,CAAC;AAEJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,uCAA8C,IAAI,GAAG,UAAU;IAC7D,OAAO;6BACoB,oBAAoB;uBAC1B,eAAe;wBACd,eAAe;yBACd,gBAAgB;2BACd,kBAAkB;+BACd,IAAI;;;;;;;;;;;;;;;;;;OAkB5B,CAAC;AACR,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,mCAA0C,SAAiB,EAAE,IAAI,GAAG,UAAU;IAC5E,OAAO;wBACe,eAAe;yBACd,gBAAgB;2BACd,kBAAkB;+BACd,IAAI;qBACd,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC;;;MAGxC,IAAA,wCAAmB,EAAC,IAAI,CAAC;;OAExB,CAAC;AACR,CAAC"}
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
import type Anthropic from "@anthropic-ai/sdk";
|
|
50
50
|
import type { Action, LoadState, Page, Stagehand } from "@browserbasehq/stagehand";
|
|
51
51
|
import { z } from "zod/v4";
|
|
52
|
-
import { type AttemptRecord, type CaptureFn, type EmailStepConfig } from "../scraper/flow-runner";
|
|
52
|
+
import { type AttemptRecord, type CaptureFn, type EmailStepConfig, type FieldValueAtFailure } from "../scraper/flow-runner";
|
|
53
53
|
import { type ProviderName } from "../scraper/session";
|
|
54
54
|
import type { TargetResolutionDiagnosticSnapshot } from "../scraper/target-resolution-diagnostic";
|
|
55
55
|
import type { Logger } from "../types/logging";
|
|
@@ -383,7 +383,7 @@ export declare function dedupeIdenticalSteps<T>(items: T[]): T[];
|
|
|
383
383
|
* wins.
|
|
384
384
|
*/
|
|
385
385
|
export declare function dedupeReplanStepsByTarget(steps: NormalizedStep[]): NormalizedStep[];
|
|
386
|
-
export declare function filterCompletedFromReplan(newSteps: readonly NormalizedStep[], completedSteps: readonly string[], failedStep: string, bodyHtmlAtFailure?: string | null): NormalizedStep[];
|
|
386
|
+
export declare function filterCompletedFromReplan(newSteps: readonly NormalizedStep[], completedSteps: readonly string[], failedStep: string, bodyHtmlAtFailure?: string | null, fieldValuesAtFailure?: readonly FieldValueAtFailure[] | null): NormalizedStep[];
|
|
387
387
|
/**
|
|
388
388
|
* Extract the field names a submit-judge rejection explicitly names as
|
|
389
389
|
* still-required, e.g. from `submit-judge-rejected: Form still displays
|
|
@@ -682,6 +682,14 @@ declare function dumpStepFailure(params: {
|
|
|
682
682
|
* page unprompted. Complements `finalObserve` (which is observe-with-step).
|
|
683
683
|
*/
|
|
684
684
|
unfocusedObserve: Action[];
|
|
685
|
+
/**
|
|
686
|
+
* Live label-keyed field values at failure time (see
|
|
687
|
+
* {@link fieldValuesAtFailureExpr}) — persisted so {@link filterCompletedFromReplan}'s
|
|
688
|
+
* resume-from-failure check can source a fill's VALUE from a signal that
|
|
689
|
+
* can actually reflect a DOM-direct `.value =` write, which `bodyOuterHtml`
|
|
690
|
+
* structurally cannot. `null` when the capture itself failed.
|
|
691
|
+
*/
|
|
692
|
+
fieldValuesAtFailure: FieldValueAtFailure[] | null;
|
|
685
693
|
/**
|
|
686
694
|
* Bounded snapshot of the submit-shaped candidate ranking at the moment
|
|
687
695
|
* resolution gave up, or `null` when the capture itself failed on the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recon-browser.d.ts","sourceRoot":"","sources":["../../src/scripts/recon-browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAMH,OAAO,KAAK,SAAS,MAAM,mBAAmB,CAAC;AAE/C,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAGnF,OAAO,EAAE,CAAC,EAAE,MAAM,QAAQ,CAAC;AA4B3B,OAAO,EACL,KAAK,aAAa,EAElB,KAAK,SAAS,EAEd,KAAK,eAAe,
|
|
1
|
+
{"version":3,"file":"recon-browser.d.ts","sourceRoot":"","sources":["../../src/scripts/recon-browser.ts"],"names":[],"mappings":"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"}
|
|
@@ -812,10 +812,11 @@ function dedupeReplanStepsByTarget(steps) {
|
|
|
812
812
|
* named still holds its expected value — resolved by parsing
|
|
813
813
|
* `bodyHtmlAtFailure` into a DOM and matching the step's field label to a
|
|
814
814
|
* control's accessible name, the same field-label-first resolution the live
|
|
815
|
-
* page cascade uses.
|
|
816
|
-
*
|
|
817
|
-
* to
|
|
818
|
-
*
|
|
815
|
+
* page cascade uses. When the field's identity can't be resolved to a
|
|
816
|
+
* specific control — no field label parses, or no control's accessible name
|
|
817
|
+
* relates to it — the step is treated as stale (kept) rather than falling
|
|
818
|
+
* back to a whole-body value search, which is unsound whenever sibling
|
|
819
|
+
* fields are designed to share a value (e.g. password + confirm password).
|
|
819
820
|
*/
|
|
820
821
|
/** Whitespace-collapsed, lowercased comparison key, mirroring `flow-runner.ts`'s `normalizeFieldLabel`. */
|
|
821
822
|
function normalizeStaleFillLabel(text) {
|
|
@@ -856,6 +857,26 @@ function accessibleNameForControl(el, window) {
|
|
|
856
857
|
return wrappingLabel.textContent;
|
|
857
858
|
return el.getAttribute("name") || id || el.getAttribute("placeholder") || "";
|
|
858
859
|
}
|
|
860
|
+
/**
|
|
861
|
+
* Exact-then-substring normalized-label match shared by {@link resolveFieldElementValue}
|
|
862
|
+
* (parsed-DOM entries) and {@link resolveFieldValueFromCapture} (live-capture
|
|
863
|
+
* entries), mirroring `flow-runner.ts`'s `findDeepLocatorCandidateByFieldLabel`.
|
|
864
|
+
*/
|
|
865
|
+
function matchByNormalizedLabel(entries, normalizedLabel) {
|
|
866
|
+
const named = entries.filter((entry) => entry.text.length > 0);
|
|
867
|
+
const exact = named.find((entry) => entry.text === normalizedLabel);
|
|
868
|
+
if (exact)
|
|
869
|
+
return exact.value;
|
|
870
|
+
const candidates = named.filter((entry) => entry.text.includes(normalizedLabel) || normalizedLabel.includes(entry.text));
|
|
871
|
+
const mostSpecific = candidates.reduce((closest, entry) => {
|
|
872
|
+
if (!closest)
|
|
873
|
+
return entry;
|
|
874
|
+
const entryDistance = Math.abs(entry.text.length - normalizedLabel.length);
|
|
875
|
+
const closestDistance = Math.abs(closest.text.length - normalizedLabel.length);
|
|
876
|
+
return entryDistance < closestDistance ? entry : closest;
|
|
877
|
+
}, null);
|
|
878
|
+
return mostSpecific?.value ?? null;
|
|
879
|
+
}
|
|
859
880
|
/**
|
|
860
881
|
* Resolves the specific input/textarea/select `bodyHtmlAtFailure` contains
|
|
861
882
|
* for the named field, using the same exact-then-substring normalized-label
|
|
@@ -872,38 +893,69 @@ function resolveFieldElementValue(bodyHtmlAtFailure, fieldLabel) {
|
|
|
872
893
|
try {
|
|
873
894
|
window.document.body.innerHTML = bodyHtmlAtFailure;
|
|
874
895
|
const controls = Array.from(window.document.querySelectorAll("input,textarea,select"));
|
|
875
|
-
const
|
|
876
|
-
.map((control) => ({
|
|
877
|
-
control,
|
|
896
|
+
const entries = controls.map((control) => ({
|
|
878
897
|
text: normalizeStaleFillLabel(accessibleNameForControl(control, window)),
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
const partial = exact ??
|
|
883
|
-
named.find((entry) => entry.text.includes(normalizedLabel) || normalizedLabel.includes(entry.text));
|
|
884
|
-
if (!partial)
|
|
885
|
-
return null;
|
|
886
|
-
return partial.control.value;
|
|
898
|
+
value: control.value,
|
|
899
|
+
}));
|
|
900
|
+
return matchByNormalizedLabel(entries, normalizedLabel);
|
|
887
901
|
}
|
|
888
902
|
finally {
|
|
889
903
|
window.close();
|
|
890
904
|
}
|
|
891
905
|
}
|
|
892
|
-
|
|
906
|
+
/**
|
|
907
|
+
* Resolves a field's VALUE from the live label-keyed capture taken at
|
|
908
|
+
* step-failure time (see `flow-runner.ts`'s `fieldValuesAtFailureExpr`),
|
|
909
|
+
* using the same normalized-label matching as `resolveFieldElementValue`.
|
|
910
|
+
* This is the authoritative value source: the capture reads each control's
|
|
911
|
+
* live `.value`/`.checked` property, which a DOM-direct fill sets without
|
|
912
|
+
* ever touching the serialized `value=` attribute `bodyOuterHtml` reflects —
|
|
913
|
+
* so a reparsed HTML snapshot can structurally never prove what a text field
|
|
914
|
+
* currently holds. Returns `null` — never a guess — when no captured
|
|
915
|
+
* field's label relates to `fieldLabel` at all.
|
|
916
|
+
*/
|
|
917
|
+
function resolveFieldValueFromCapture(fieldValuesAtFailure, fieldLabel) {
|
|
918
|
+
const normalizedLabel = normalizeStaleFillLabel(fieldLabel);
|
|
919
|
+
if (!normalizedLabel)
|
|
920
|
+
return null;
|
|
921
|
+
const entries = fieldValuesAtFailure.map((field) => ({
|
|
922
|
+
text: normalizeStaleFillLabel(field.label),
|
|
923
|
+
value: field.value,
|
|
924
|
+
}));
|
|
925
|
+
return matchByNormalizedLabel(entries, normalizedLabel);
|
|
926
|
+
}
|
|
927
|
+
function filterCompletedFromReplan(newSteps, completedSteps, failedStep, bodyHtmlAtFailure, fieldValuesAtFailure) {
|
|
893
928
|
const isStaleFill = (step) => {
|
|
894
|
-
if (!bodyHtmlAtFailure)
|
|
929
|
+
if (!bodyHtmlAtFailure && !fieldValuesAtFailure)
|
|
895
930
|
return false;
|
|
896
931
|
const parsedFill = (0, flow_runner_1.parseFillStep)(step);
|
|
897
932
|
const fieldLabel = parsedFill?.fieldLabel;
|
|
898
|
-
if (fieldLabel && parsedFill?.value) {
|
|
899
|
-
const fieldValue = resolveFieldElementValue(bodyHtmlAtFailure, fieldLabel);
|
|
900
|
-
if (fieldValue !== null)
|
|
901
|
-
return fieldValue !== parsedFill.value;
|
|
902
|
-
}
|
|
903
933
|
const value = parsedFill?.value ?? (0, flow_runner_1.parseFillValueIntent)(step)?.value;
|
|
904
934
|
if (!value)
|
|
905
935
|
return false;
|
|
906
|
-
|
|
936
|
+
if (fieldLabel) {
|
|
937
|
+
// Live-captured value is authoritative when present — it can prove a
|
|
938
|
+
// DOM-direct fill survived even though the field's static attribute
|
|
939
|
+
// shows empty (see resolveFieldValueFromCapture). Only fall back to
|
|
940
|
+
// the structural bodyHtmlAtFailure re-parse when the capture has no
|
|
941
|
+
// entry for this field (e.g. capture itself failed, or this call site
|
|
942
|
+
// predates it).
|
|
943
|
+
const liveValue = fieldValuesAtFailure
|
|
944
|
+
? resolveFieldValueFromCapture(fieldValuesAtFailure, fieldLabel)
|
|
945
|
+
: null;
|
|
946
|
+
if (liveValue !== null)
|
|
947
|
+
return liveValue !== value;
|
|
948
|
+
const fieldValue = bodyHtmlAtFailure
|
|
949
|
+
? resolveFieldElementValue(bodyHtmlAtFailure, fieldLabel)
|
|
950
|
+
: null;
|
|
951
|
+
if (fieldValue !== null)
|
|
952
|
+
return fieldValue !== value;
|
|
953
|
+
}
|
|
954
|
+
// The step's field identity couldn't be resolved to a specific control in the
|
|
955
|
+
// failure-time DOM; a whole-body value search is unsound when sibling fields
|
|
956
|
+
// (e.g. password + confirm password) share the same value, so treat the step
|
|
957
|
+
// as stale rather than risk wrongly dropping a still-required field.
|
|
958
|
+
return true;
|
|
907
959
|
};
|
|
908
960
|
const completed = new Set(completedSteps.filter((s) => !isStaleFill(s)));
|
|
909
961
|
return newSteps.filter((s) => s.instruction === failedStep || !completed.has(s.instruction));
|
|
@@ -918,8 +970,18 @@ function normalizeInstruction(instruction) {
|
|
|
918
970
|
* Quoted phrases are the strongest, lowest-noise signal a flow author or the
|
|
919
971
|
* replanner gives for "which control": comparing these directly avoids false
|
|
920
972
|
* positives from prose that merely mentions the same page section.
|
|
973
|
+
*
|
|
974
|
+
* For a fill-shaped instruction (`parseFillStep` matches), the only quoted
|
|
975
|
+
* substring is the VALUE being typed, not the field's identity — two sibling
|
|
976
|
+
* fields sharing one value (e.g. a password and its confirmation) would
|
|
977
|
+
* otherwise extract identical "labels" and collide in every consumer that
|
|
978
|
+
* keys off this function. In that case the field label itself is returned
|
|
979
|
+
* instead of the raw quoted match.
|
|
921
980
|
*/
|
|
922
981
|
function extractQuotedLabels(instruction) {
|
|
982
|
+
const fieldLabel = (0, flow_runner_1.parseFillStep)(instruction)?.fieldLabel;
|
|
983
|
+
if (fieldLabel)
|
|
984
|
+
return [normalizeInstruction(fieldLabel)];
|
|
923
985
|
const matches = instruction.matchAll(/['"]([^'"]{2,80})['"]/g);
|
|
924
986
|
return [...matches].map((m) => normalizeInstruction(m[1]));
|
|
925
987
|
}
|
|
@@ -1787,6 +1849,7 @@ function dumpStepFailure(params) {
|
|
|
1787
1849
|
finalObserve: params.finalObserve,
|
|
1788
1850
|
unfocusedObserve: params.unfocusedObserve,
|
|
1789
1851
|
bodyOuterHtml: params.bodyOuterHtml,
|
|
1852
|
+
fieldValuesAtFailure: params.fieldValuesAtFailure,
|
|
1790
1853
|
recentCaptures: params.recentCaptures.slice(-5),
|
|
1791
1854
|
targetResolutionDiagnostic: params.targetResolutionDiagnostic,
|
|
1792
1855
|
};
|
|
@@ -2565,16 +2628,19 @@ async function main() {
|
|
|
2565
2628
|
// failed step's re-emission. originalRemaining is re-appended below.
|
|
2566
2629
|
// The untruncated failure-time DOM re-verifies completed fills so a
|
|
2567
2630
|
// silently-reset field isn't trusted as still-completed.
|
|
2568
|
-
const bodyHtmlAtFailure = (() => {
|
|
2631
|
+
const { bodyHtmlAtFailure, fieldValuesAtFailure } = (() => {
|
|
2569
2632
|
try {
|
|
2570
2633
|
const dump = JSON.parse((0, node_fs_1.readFileSync)(dumpPath, "utf8"));
|
|
2571
|
-
return
|
|
2634
|
+
return {
|
|
2635
|
+
bodyHtmlAtFailure: dump.bodyOuterHtml ?? null,
|
|
2636
|
+
fieldValuesAtFailure: dump.fieldValuesAtFailure ?? null,
|
|
2637
|
+
};
|
|
2572
2638
|
}
|
|
2573
2639
|
catch {
|
|
2574
|
-
return null;
|
|
2640
|
+
return { bodyHtmlAtFailure: null, fieldValuesAtFailure: null };
|
|
2575
2641
|
}
|
|
2576
2642
|
})();
|
|
2577
|
-
const newSteps = filterCompletedFromReplan(rawNewSteps, completedSteps, step.instruction, bodyHtmlAtFailure);
|
|
2643
|
+
const newSteps = filterCompletedFromReplan(rawNewSteps, completedSteps, step.instruction, bodyHtmlAtFailure, fieldValuesAtFailure);
|
|
2578
2644
|
const droppedCompleted = rawNewSteps.length - newSteps.length;
|
|
2579
2645
|
if (droppedCompleted > 0) {
|
|
2580
2646
|
logger.info(`replan #${replanIndex}: dropped ${droppedCompleted} bridge step(s) that re-ran already-completed steps`);
|