@runcofactor/cli 0.13.0 → 0.15.1
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/account-62I7FG5G.js +255 -0
- package/dist/account-62I7FG5G.js.map +1 -0
- package/dist/{api-catalog-7HLEN7C2.js → api-catalog-CAJUASVC.js} +5 -5
- package/dist/{attachment-OVNQD6Z2.js → attachment-RL4AZUJE.js} +5 -5
- package/dist/augmentor-GAF3MFY6.js +198 -0
- package/dist/augmentor-GAF3MFY6.js.map +1 -0
- package/dist/{auth-VUHL74FH.js → auth-DURHUZDW.js} +3 -3
- package/dist/{chunk-YN763NWQ.js → chunk-26U3DGUM.js} +10 -4
- package/dist/chunk-26U3DGUM.js.map +1 -0
- package/dist/{chunk-JZMJUPZP.js → chunk-32P26BZT.js} +3 -3
- package/dist/chunk-32P26BZT.js.map +1 -0
- package/dist/{chunk-QQVWGWPI.js → chunk-5R4HMSNX.js} +8561 -1511
- package/dist/chunk-5R4HMSNX.js.map +1 -0
- package/dist/{chunk-VGTKUOYS.js → chunk-AQPJQ5AE.js} +2 -2
- package/dist/{chunk-CQE46HSM.js → chunk-CFJXYPTF.js} +14 -8
- package/dist/chunk-CFJXYPTF.js.map +1 -0
- package/dist/{chunk-NL7CVG56.js → chunk-CJEKEW7R.js} +57 -10
- package/dist/chunk-CJEKEW7R.js.map +1 -0
- package/dist/{chunk-Z5LUTUDN.js → chunk-G5SXUXSU.js} +3 -3
- package/dist/{chunk-ZTOE3ND3.js → chunk-HKQ5XQAQ.js} +4 -4
- package/dist/{chunk-PZ4LCN6K.js → chunk-IGHDIWZU.js} +2 -2
- package/dist/{chunk-QGI4UCJX.js → chunk-IWKJQZJQ.js} +124 -74
- package/dist/chunk-IWKJQZJQ.js.map +1 -0
- package/dist/{chunk-ZD3KHESI.js → chunk-KRWRUU6R.js} +27 -7
- package/dist/chunk-KRWRUU6R.js.map +1 -0
- package/dist/{chunk-CRHPDPRS.js → chunk-PXFDH6YL.js} +63 -8
- package/dist/{chunk-CRHPDPRS.js.map → chunk-PXFDH6YL.js.map} +1 -1
- package/dist/{chunk-EJ4U242G.js → chunk-UZ2ZA5A6.js} +2 -2
- package/dist/{chunk-EEN2TZUQ.js → chunk-VKBTI5EF.js} +3 -3
- package/dist/{chunk-ENDHMYEJ.js → chunk-ZXRVFFCY.js} +3 -3
- package/dist/{credential-LO2SEEHU.js → credential-JGVSEGVH.js} +5 -5
- package/dist/{credential-template-ZN7W7734.js → credential-template-CWWMOKB2.js} +5 -5
- package/dist/{debug-workflow-R3RYYAXK.js → debug-workflow-BXRU72YZ.js} +5 -5
- package/dist/{docs-DIAFBDXQ.js → docs-PVBXPTGR.js} +95 -11
- package/dist/docs-PVBXPTGR.js.map +1 -0
- package/dist/{doctor-NZPUSCRE.js → doctor-RHMKD4W5.js} +3 -3
- package/dist/{environment-RQVU4P5M.js → environment-WZKIO3R3.js} +5 -5
- package/dist/{feature-flag-XG26RURR.js → feature-flag-K5REGGDY.js} +98 -12
- package/dist/feature-flag-K5REGGDY.js.map +1 -0
- package/dist/index.js +107 -51
- package/dist/index.js.map +1 -1
- package/dist/{init-EDNLKGPT.js → init-FFUZO5D7.js} +5 -5
- package/dist/{install-FYZ3HNZK.js → install-XRKEQAFZ.js} +5 -5
- package/dist/{issues-NNRVTJ4L.js → issues-I3V6GEXU.js} +5 -5
- package/dist/{knobs-A2BOBH22.js → knobs-6WLJMB44.js} +7 -6
- package/dist/knobs-6WLJMB44.js.map +1 -0
- package/dist/{list-F33VZ4BJ.js → list-PHC7VYNS.js} +5 -5
- package/dist/{local-DQDTM3XA.js → local-VGYRSW22.js} +7 -7
- package/dist/{login-BUMVIB36.js → login-QPU2BKG2.js} +5 -5
- package/dist/{mcp-B5Y5CDMQ.js → mcp-LA452TOA.js} +9 -9
- package/dist/{mcp-B5Y5CDMQ.js.map → mcp-LA452TOA.js.map} +1 -1
- package/dist/{pdf-extract-ABWV3L5X.js → pdf-extract-YHE54XU4.js} +2 -2
- package/dist/product-RSZV5HMB.js +346 -0
- package/dist/product-RSZV5HMB.js.map +1 -0
- package/dist/{property-NJ4SRXQG.js → property-YP4GHQAR.js} +5 -5
- package/dist/{psql-VBZFCMNR.js → psql-XGLBI6T7.js} +3 -3
- package/dist/{record-WAO36O7G.js → record-KWKHP2ZY.js} +6 -6
- package/dist/{redis-DHZXHL4S.js → redis-VJGCUJPV.js} +3 -3
- package/dist/redis-VJGCUJPV.js.map +1 -0
- package/dist/{release-STJKUKTE.js → release-NDRHPW6V.js} +5 -5
- package/dist/{sandbox-DWSGLY7B.js → sandbox-OOCANWOG.js} +51 -7
- package/dist/sandbox-OOCANWOG.js.map +1 -0
- package/dist/{scenarios-HCIDY725.js → scenarios-2HRLCGFY.js} +5 -5
- package/dist/{session-Y5RHU54D.js → session-M4ULYDYP.js} +8 -9
- package/dist/session-M4ULYDYP.js.map +1 -0
- package/dist/{skill-23WAHUOB.js → skill-4DGPRDUC.js} +10 -10
- package/dist/{skill-23WAHUOB.js.map → skill-4DGPRDUC.js.map} +1 -1
- package/dist/skills/debug-run/SKILL.md +7 -1
- package/dist/skills/debug-run/history/1.3.1.md +279 -0
- package/dist/skills/debug-run/version.json +1 -1
- package/dist/skills/optimize-cache/SKILL.md +41 -4
- package/dist/{spec-LM5XHOQ5.js → spec-XZ2TKUFZ.js} +5 -5
- package/dist/{src-BGDRMOKC.js → src-2FK3JHGW.js} +315 -104
- package/dist/src-2FK3JHGW.js.map +1 -0
- package/dist/{src-NCJPUAE6.js → src-CV57ZD6I.js} +10 -8
- package/dist/{src-22RI5VP2.js → src-HL7HEJIW.js} +2 -2
- package/dist/{src-Y3K7UJEF.js → src-OU7544PM.js} +6 -4
- package/dist/{start-SWY55CZX.js → start-IYKF3C3X.js} +5 -5
- package/dist/{tag-YSU2XXPI.js → tag-T45MMSCH.js} +6 -6
- package/dist/{task-NLBKLD7D.js → task-MCUHAVTD.js} +5 -5
- package/dist/{test-suite-QCPWZ2LS.js → test-suite-BICBRSBP.js} +10 -8
- package/dist/{test-suite-QCPWZ2LS.js.map → test-suite-BICBRSBP.js.map} +1 -1
- package/dist/trace-2BAPMYAS.js +16 -0
- package/dist/{triage-TT4BMDBU.js → triage-M3RZ2ASB.js} +6 -6
- package/dist/{upgrade-6ZUFETKX.js → upgrade-4QCRAUHP.js} +3 -3
- package/dist/{workflow-2CX3ZNOQ.js → workflow-4J23FV7K.js} +86 -15
- package/dist/workflow-4J23FV7K.js.map +1 -0
- package/dist/{workflow-cache-GXNE6SU2.js → workflow-cache-XPSK6KC7.js} +26 -13
- package/dist/workflow-cache-XPSK6KC7.js.map +1 -0
- package/dist/{workflow-debug-PRX3DWGD.js → workflow-debug-W4USZH35.js} +9 -9
- package/dist/{workflow-proposals-BW327WGL.js → workflow-proposals-5E3DTYZB.js} +5 -7
- package/dist/workflow-proposals-5E3DTYZB.js.map +1 -0
- package/package.json +5 -1
- package/dist/chunk-CQE46HSM.js.map +0 -1
- package/dist/chunk-JZMJUPZP.js.map +0 -1
- package/dist/chunk-NL7CVG56.js.map +0 -1
- package/dist/chunk-QGI4UCJX.js.map +0 -1
- package/dist/chunk-QQVWGWPI.js.map +0 -1
- package/dist/chunk-YN763NWQ.js.map +0 -1
- package/dist/chunk-ZD3KHESI.js.map +0 -1
- package/dist/docs-DIAFBDXQ.js.map +0 -1
- package/dist/feature-flag-XG26RURR.js.map +0 -1
- package/dist/knobs-A2BOBH22.js.map +0 -1
- package/dist/redis-DHZXHL4S.js.map +0 -1
- package/dist/sandbox-DWSGLY7B.js.map +0 -1
- package/dist/session-Y5RHU54D.js.map +0 -1
- package/dist/src-BGDRMOKC.js.map +0 -1
- package/dist/trace-A3ZY6K26.js +0 -16
- package/dist/workflow-2CX3ZNOQ.js.map +0 -1
- package/dist/workflow-cache-GXNE6SU2.js.map +0 -1
- package/dist/workflow-proposals-BW327WGL.js.map +0 -1
- /package/dist/{api-catalog-7HLEN7C2.js.map → api-catalog-CAJUASVC.js.map} +0 -0
- /package/dist/{attachment-OVNQD6Z2.js.map → attachment-RL4AZUJE.js.map} +0 -0
- /package/dist/{auth-VUHL74FH.js.map → auth-DURHUZDW.js.map} +0 -0
- /package/dist/{chunk-VGTKUOYS.js.map → chunk-AQPJQ5AE.js.map} +0 -0
- /package/dist/{chunk-Z5LUTUDN.js.map → chunk-G5SXUXSU.js.map} +0 -0
- /package/dist/{chunk-ZTOE3ND3.js.map → chunk-HKQ5XQAQ.js.map} +0 -0
- /package/dist/{chunk-PZ4LCN6K.js.map → chunk-IGHDIWZU.js.map} +0 -0
- /package/dist/{chunk-EJ4U242G.js.map → chunk-UZ2ZA5A6.js.map} +0 -0
- /package/dist/{chunk-EEN2TZUQ.js.map → chunk-VKBTI5EF.js.map} +0 -0
- /package/dist/{chunk-ENDHMYEJ.js.map → chunk-ZXRVFFCY.js.map} +0 -0
- /package/dist/{credential-LO2SEEHU.js.map → credential-JGVSEGVH.js.map} +0 -0
- /package/dist/{credential-template-ZN7W7734.js.map → credential-template-CWWMOKB2.js.map} +0 -0
- /package/dist/{debug-workflow-R3RYYAXK.js.map → debug-workflow-BXRU72YZ.js.map} +0 -0
- /package/dist/{doctor-NZPUSCRE.js.map → doctor-RHMKD4W5.js.map} +0 -0
- /package/dist/{environment-RQVU4P5M.js.map → environment-WZKIO3R3.js.map} +0 -0
- /package/dist/{init-EDNLKGPT.js.map → init-FFUZO5D7.js.map} +0 -0
- /package/dist/{install-FYZ3HNZK.js.map → install-XRKEQAFZ.js.map} +0 -0
- /package/dist/{issues-NNRVTJ4L.js.map → issues-I3V6GEXU.js.map} +0 -0
- /package/dist/{list-F33VZ4BJ.js.map → list-PHC7VYNS.js.map} +0 -0
- /package/dist/{local-DQDTM3XA.js.map → local-VGYRSW22.js.map} +0 -0
- /package/dist/{login-BUMVIB36.js.map → login-QPU2BKG2.js.map} +0 -0
- /package/dist/{pdf-extract-ABWV3L5X.js.map → pdf-extract-YHE54XU4.js.map} +0 -0
- /package/dist/{property-NJ4SRXQG.js.map → property-YP4GHQAR.js.map} +0 -0
- /package/dist/{psql-VBZFCMNR.js.map → psql-XGLBI6T7.js.map} +0 -0
- /package/dist/{record-WAO36O7G.js.map → record-KWKHP2ZY.js.map} +0 -0
- /package/dist/{release-STJKUKTE.js.map → release-NDRHPW6V.js.map} +0 -0
- /package/dist/{scenarios-HCIDY725.js.map → scenarios-2HRLCGFY.js.map} +0 -0
- /package/dist/{spec-LM5XHOQ5.js.map → spec-XZ2TKUFZ.js.map} +0 -0
- /package/dist/{src-NCJPUAE6.js.map → src-CV57ZD6I.js.map} +0 -0
- /package/dist/{src-22RI5VP2.js.map → src-HL7HEJIW.js.map} +0 -0
- /package/dist/{src-Y3K7UJEF.js.map → src-OU7544PM.js.map} +0 -0
- /package/dist/{start-SWY55CZX.js.map → start-IYKF3C3X.js.map} +0 -0
- /package/dist/{tag-YSU2XXPI.js.map → tag-T45MMSCH.js.map} +0 -0
- /package/dist/{task-NLBKLD7D.js.map → task-MCUHAVTD.js.map} +0 -0
- /package/dist/{trace-A3ZY6K26.js.map → trace-2BAPMYAS.js.map} +0 -0
- /package/dist/{triage-TT4BMDBU.js.map → triage-M3RZ2ASB.js.map} +0 -0
- /package/dist/{upgrade-6ZUFETKX.js.map → upgrade-4QCRAUHP.js.map} +0 -0
- /package/dist/{workflow-debug-PRX3DWGD.js.map → workflow-debug-W4USZH35.js.map} +0 -0
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
parseTraceActions,
|
|
4
|
+
reconstructSnapshots,
|
|
5
|
+
toMutationIndex
|
|
6
|
+
} from "./chunk-PXFDH6YL.js";
|
|
5
7
|
import {
|
|
6
8
|
buildLocatorString
|
|
7
9
|
} from "./chunk-5GD47G2D.js";
|
|
8
10
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
applyCustomAugmentors,
|
|
12
|
+
captureSubstrateV2,
|
|
13
|
+
parseSnapshot
|
|
14
|
+
} from "./chunk-5R4HMSNX.js";
|
|
11
15
|
import "./chunk-JWHYXEA2.js";
|
|
12
16
|
import {
|
|
13
17
|
MACRO_PATTERN,
|
|
14
18
|
isVolatileIdentifier,
|
|
15
19
|
stableAttrSelector,
|
|
16
20
|
stableIdentifierPrefix
|
|
17
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-IWKJQZJQ.js";
|
|
18
22
|
import "./chunk-6LEZCKKV.js";
|
|
19
23
|
import {
|
|
20
24
|
consoleLogger
|
|
21
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-KRWRUU6R.js";
|
|
22
26
|
import "./chunk-VKVL7WBN.js";
|
|
23
27
|
|
|
24
28
|
// ../workflow-cache/src/logger.ts
|
|
25
29
|
var activeLogger = consoleLogger;
|
|
26
|
-
function setWorkflowCacheLogger(
|
|
27
|
-
activeLogger =
|
|
30
|
+
function setWorkflowCacheLogger(logger4) {
|
|
31
|
+
activeLogger = logger4;
|
|
28
32
|
}
|
|
29
33
|
function createLogger(bindings) {
|
|
30
34
|
if (!bindings || Object.keys(bindings).length === 0) {
|
|
@@ -53,8 +57,8 @@ function sortObjectKeys(obj) {
|
|
|
53
57
|
}
|
|
54
58
|
if (obj !== null && typeof obj === "object") {
|
|
55
59
|
const sorted = Object.keys(obj).sort().reduce(
|
|
56
|
-
(acc,
|
|
57
|
-
acc[
|
|
60
|
+
(acc, key2) => {
|
|
61
|
+
acc[key2] = sortObjectKeys(obj[key2]);
|
|
58
62
|
return acc;
|
|
59
63
|
},
|
|
60
64
|
{}
|
|
@@ -64,10 +68,26 @@ function sortObjectKeys(obj) {
|
|
|
64
68
|
return obj;
|
|
65
69
|
}
|
|
66
70
|
function generateNodeHash(input) {
|
|
71
|
+
return hashWithPrefix(input, HASH_VERSION);
|
|
72
|
+
}
|
|
73
|
+
function generateNodeHashV3(input) {
|
|
74
|
+
const { playbookSteps: _playbookSteps, inlineAssertions, ...identity } = input;
|
|
75
|
+
const v3Input = {
|
|
76
|
+
...identity,
|
|
77
|
+
...inlineAssertions ? {
|
|
78
|
+
inlineAssertions: inlineAssertions.map(({ condition, agentic }) => ({
|
|
79
|
+
condition,
|
|
80
|
+
...agentic !== void 0 ? { agentic } : {}
|
|
81
|
+
}))
|
|
82
|
+
} : {}
|
|
83
|
+
};
|
|
84
|
+
return hashWithPrefix(v3Input, "v3");
|
|
85
|
+
}
|
|
86
|
+
function hashWithPrefix(input, version) {
|
|
67
87
|
const sortedInput = sortObjectKeys(input);
|
|
68
88
|
const stableJson = JSON.stringify(sortedInput);
|
|
69
89
|
const hash = createHash("sha256").update(stableJson).digest("hex").slice(0, 16);
|
|
70
|
-
return `${
|
|
90
|
+
return `${version}:${hash}`;
|
|
71
91
|
}
|
|
72
92
|
|
|
73
93
|
// ../workflow-cache/src/build-locator.ts
|
|
@@ -95,6 +115,15 @@ function buildLocator(snapshot, ref, variableValues = {}) {
|
|
|
95
115
|
const frameContext = frameContextFor(target.el);
|
|
96
116
|
const baseDynamicText = buildDynamicText(target);
|
|
97
117
|
const ancestors = ancestorChain(target);
|
|
118
|
+
const augmentorAnchor = target.el.augmentorAnchor;
|
|
119
|
+
if (augmentorAnchor) {
|
|
120
|
+
return {
|
|
121
|
+
selectors: applyContexts({ css: augmentorAnchor }, frameContext, baseDynamicText),
|
|
122
|
+
predicate: "augmentorAnchor",
|
|
123
|
+
bindings: allBindings,
|
|
124
|
+
irreducible: false
|
|
125
|
+
};
|
|
126
|
+
}
|
|
98
127
|
const uniqueTestId = pickUniqueTestId(target, flat);
|
|
99
128
|
if (uniqueTestId) {
|
|
100
129
|
return {
|
|
@@ -366,12 +395,12 @@ function buildRowScopedOrdinalLocator(args) {
|
|
|
366
395
|
const buttonRefs = collectRoleRefs(anchor.el, "button");
|
|
367
396
|
const ordinal = buttonRefs.indexOf(args.target.el.ref);
|
|
368
397
|
if (ordinal < 0) continue;
|
|
369
|
-
const [
|
|
398
|
+
const [key2, value] = match;
|
|
370
399
|
return {
|
|
371
|
-
locator: `getByRole('${escapeLocatorString(anchor.el.role)}').filter({ hasText: '{{var.${
|
|
400
|
+
locator: `getByRole('${escapeLocatorString(anchor.el.role)}').filter({ hasText: '{{var.${key2}}}' }).getByRole('button').nth(${ordinal})`,
|
|
372
401
|
anchor,
|
|
373
402
|
innerAncestors: args.ancestors.slice(i + 1),
|
|
374
|
-
key,
|
|
403
|
+
key: key2,
|
|
375
404
|
value
|
|
376
405
|
};
|
|
377
406
|
}
|
|
@@ -392,8 +421,8 @@ function escapeLocatorString(value) {
|
|
|
392
421
|
var MIN_TEMPLATING_LENGTH = 3;
|
|
393
422
|
function templateAll(flat, variableValues) {
|
|
394
423
|
const summary = /* @__PURE__ */ new Map();
|
|
395
|
-
const compiled = Object.entries(variableValues).filter(([, v]) => typeof v === "string" && v.length >= MIN_TEMPLATING_LENGTH).map(([
|
|
396
|
-
key,
|
|
424
|
+
const compiled = Object.entries(variableValues).filter(([, v]) => typeof v === "string" && v.length >= MIN_TEMPLATING_LENGTH).map(([key2, value]) => ({
|
|
425
|
+
key: key2,
|
|
397
426
|
value,
|
|
398
427
|
regex: new RegExp(`(^|\\W)${escapeRegex(value)}(?=\\W|$)`, "g")
|
|
399
428
|
}));
|
|
@@ -870,12 +899,12 @@ function findRowVariableScope(args) {
|
|
|
870
899
|
continue;
|
|
871
900
|
}
|
|
872
901
|
const anchorText = collectSubtreeText(anchor.el);
|
|
873
|
-
for (const [
|
|
902
|
+
for (const [key2, value] of entries) {
|
|
874
903
|
if (!textContainsValue(anchorText, value)) continue;
|
|
875
904
|
return {
|
|
876
905
|
anchor,
|
|
877
906
|
innerAncestors: args.ancestors.slice(i + 1),
|
|
878
|
-
key,
|
|
907
|
+
key: key2,
|
|
879
908
|
value
|
|
880
909
|
};
|
|
881
910
|
}
|
|
@@ -977,9 +1006,9 @@ function parseLine(line) {
|
|
|
977
1006
|
if (cleanContent.startsWith("/")) {
|
|
978
1007
|
const colonIdx = cleanContent.indexOf(":");
|
|
979
1008
|
if (colonIdx !== -1) {
|
|
980
|
-
const
|
|
1009
|
+
const key2 = cleanContent.slice(1, colonIdx).trim();
|
|
981
1010
|
const value = cleanContent.slice(colonIdx + 1).trim();
|
|
982
|
-
return { indent, role: "_property", attributes: { [
|
|
1011
|
+
return { indent, role: "_property", attributes: { [key2]: value } };
|
|
983
1012
|
}
|
|
984
1013
|
}
|
|
985
1014
|
if (withoutBrackets.startsWith('"') && withoutBrackets.endsWith('"')) {
|
|
@@ -1005,9 +1034,9 @@ function parseLine(line) {
|
|
|
1005
1034
|
const attributes = {};
|
|
1006
1035
|
const attrMatches = cleanContent.matchAll(/\[(\w+)=([^\]]+)\]/g);
|
|
1007
1036
|
for (const match of attrMatches) {
|
|
1008
|
-
const [,
|
|
1009
|
-
if (
|
|
1010
|
-
attributes[
|
|
1037
|
+
const [, key2, value] = match;
|
|
1038
|
+
if (key2 !== "ref") {
|
|
1039
|
+
attributes[key2] = value;
|
|
1011
1040
|
}
|
|
1012
1041
|
}
|
|
1013
1042
|
return {
|
|
@@ -1414,11 +1443,11 @@ function escapeForLocatorString(value) {
|
|
|
1414
1443
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
1415
1444
|
}
|
|
1416
1445
|
function hydrateLocatorVariables(locatorStr, variableValues) {
|
|
1417
|
-
return locatorStr.replace(/\{\{var\.([a-zA-Z0-9_]+)\}\}/g, (_match,
|
|
1418
|
-
const value = variableValues[
|
|
1446
|
+
return locatorStr.replace(/\{\{var\.([a-zA-Z0-9_]+)\}\}/g, (_match, key2) => {
|
|
1447
|
+
const value = variableValues[key2];
|
|
1419
1448
|
if (value === void 0) {
|
|
1420
|
-
getLogger().warn("[LocatorParser] Variable placeholder not found in values", { key });
|
|
1421
|
-
return `{{var.${
|
|
1449
|
+
getLogger().warn("[LocatorParser] Variable placeholder not found in values", { key: key2 });
|
|
1450
|
+
return `{{var.${key2}}}`;
|
|
1422
1451
|
}
|
|
1423
1452
|
return escapeForLocatorString(value);
|
|
1424
1453
|
});
|
|
@@ -1585,7 +1614,7 @@ function parseObjectArg(input) {
|
|
|
1585
1614
|
for (const pair of pairs) {
|
|
1586
1615
|
const colonIdx = pair.indexOf(":");
|
|
1587
1616
|
if (colonIdx === -1) continue;
|
|
1588
|
-
const
|
|
1617
|
+
const key2 = pair.slice(0, colonIdx).trim().replace(/^['"]|['"]$/g, "");
|
|
1589
1618
|
const rawValue = pair.slice(colonIdx + 1).trim();
|
|
1590
1619
|
if (rawValue.startsWith("'") || rawValue.startsWith('"')) {
|
|
1591
1620
|
const q = rawValue[0];
|
|
@@ -1594,20 +1623,20 @@ function parseObjectArg(input) {
|
|
|
1594
1623
|
if (rawValue[end] === "\\") end++;
|
|
1595
1624
|
end++;
|
|
1596
1625
|
}
|
|
1597
|
-
obj[
|
|
1626
|
+
obj[key2] = rawValue.slice(1, end).replace(/\\'/g, "'").replace(/\\"/g, '"');
|
|
1598
1627
|
} else if (rawValue.startsWith("/")) {
|
|
1599
1628
|
const regexMatch = rawValue.match(/^\/([^/]+)\/([gimsuy]*)/);
|
|
1600
1629
|
if (regexMatch) {
|
|
1601
|
-
obj[
|
|
1630
|
+
obj[key2] = new RegExp(regexMatch[1], regexMatch[2]);
|
|
1602
1631
|
}
|
|
1603
1632
|
} else if (rawValue === "true") {
|
|
1604
|
-
obj[
|
|
1633
|
+
obj[key2] = true;
|
|
1605
1634
|
} else if (rawValue === "false") {
|
|
1606
|
-
obj[
|
|
1635
|
+
obj[key2] = false;
|
|
1607
1636
|
} else if (/^-?\d+$/.test(rawValue)) {
|
|
1608
|
-
obj[
|
|
1637
|
+
obj[key2] = parseInt(rawValue, 10);
|
|
1609
1638
|
} else {
|
|
1610
|
-
obj[
|
|
1639
|
+
obj[key2] = rawValue;
|
|
1611
1640
|
}
|
|
1612
1641
|
}
|
|
1613
1642
|
return { value: obj, rest };
|
|
@@ -3368,8 +3397,8 @@ async function resolveElement(page, selectors, _timeoutMs, options) {
|
|
|
3368
3397
|
errors.push(`CSS selector ("${selectors.css}") found no matches`);
|
|
3369
3398
|
}
|
|
3370
3399
|
if (selectors.dynamicText && options?.variableValues && selectors.role && !requireSelect && !skipHeuristicFallbacks) {
|
|
3371
|
-
const { key } = selectors.dynamicText;
|
|
3372
|
-
const currentValue = options.variableValues[
|
|
3400
|
+
const { key: key2 } = selectors.dynamicText;
|
|
3401
|
+
const currentValue = options.variableValues[key2];
|
|
3373
3402
|
if (currentValue) {
|
|
3374
3403
|
logger().debug("[ElementResolver] Trying structural fallback for dynamic text", {
|
|
3375
3404
|
role: selectors.role.role,
|
|
@@ -3585,15 +3614,15 @@ function deriveSelectorsFromElementInfo(elementInfo) {
|
|
|
3585
3614
|
}
|
|
3586
3615
|
function sanitizeArgsForCache(args) {
|
|
3587
3616
|
const sanitized = {};
|
|
3588
|
-
for (const [
|
|
3589
|
-
if (
|
|
3617
|
+
for (const [key2, value] of Object.entries(args)) {
|
|
3618
|
+
if (key2 === "ref" || key2 === "startRef" || key2 === "endRef") {
|
|
3590
3619
|
continue;
|
|
3591
3620
|
}
|
|
3592
|
-
if (
|
|
3621
|
+
if (key2 === "signal" || key2 === "timeoutMs") {
|
|
3593
3622
|
continue;
|
|
3594
3623
|
}
|
|
3595
3624
|
if (Array.isArray(value)) {
|
|
3596
|
-
sanitized[
|
|
3625
|
+
sanitized[key2] = value.map((item) => {
|
|
3597
3626
|
if (typeof item === "object" && item !== null) {
|
|
3598
3627
|
return sanitizeArgsForCache(item);
|
|
3599
3628
|
}
|
|
@@ -3601,7 +3630,7 @@ function sanitizeArgsForCache(args) {
|
|
|
3601
3630
|
});
|
|
3602
3631
|
continue;
|
|
3603
3632
|
}
|
|
3604
|
-
sanitized[
|
|
3633
|
+
sanitized[key2] = value;
|
|
3605
3634
|
}
|
|
3606
3635
|
return sanitized;
|
|
3607
3636
|
}
|
|
@@ -3754,12 +3783,12 @@ async function findRowAnchor(originalLocator, timeoutMs) {
|
|
|
3754
3783
|
const t = raw.trim();
|
|
3755
3784
|
if (t.length < 3) return;
|
|
3756
3785
|
if (t.length > 120) return;
|
|
3757
|
-
const
|
|
3758
|
-
if (
|
|
3759
|
-
if (targetText.length > 0 &&
|
|
3760
|
-
if (targetText.length > 0 && targetText.includes(
|
|
3761
|
-
if (seen.has(
|
|
3762
|
-
seen.add(
|
|
3786
|
+
const key2 = t.toLowerCase();
|
|
3787
|
+
if (key2 === targetText) return;
|
|
3788
|
+
if (targetText.length > 0 && key2.includes(targetText)) return;
|
|
3789
|
+
if (targetText.length > 0 && targetText.includes(key2)) return;
|
|
3790
|
+
if (seen.has(key2)) return;
|
|
3791
|
+
seen.add(key2);
|
|
3763
3792
|
texts.push(t);
|
|
3764
3793
|
};
|
|
3765
3794
|
if (ariaLabel) pushText(ariaLabel);
|
|
@@ -3814,7 +3843,7 @@ async function findRowAnchor(originalLocator, timeoutMs) {
|
|
|
3814
3843
|
}
|
|
3815
3844
|
async function discoverParentContext(page, selectors, selectorType, originalLocator, options) {
|
|
3816
3845
|
const { timeoutMs, maxParentDepth } = options;
|
|
3817
|
-
const
|
|
3846
|
+
const logger4 = getLogger2();
|
|
3818
3847
|
const context = selectors.frameContext?.selector ? page.frameLocator(selectors.frameContext.selector) : page;
|
|
3819
3848
|
try {
|
|
3820
3849
|
const rowCandidate = await findRowAnchor(originalLocator, timeoutMs);
|
|
@@ -3833,7 +3862,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
3833
3862
|
if (!resolved) continue;
|
|
3834
3863
|
const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);
|
|
3835
3864
|
if (!isSame) continue;
|
|
3836
|
-
|
|
3865
|
+
logger4.debug("[SelectorDerivation] Found unique row anchor", {
|
|
3837
3866
|
selectorType,
|
|
3838
3867
|
parentContext: candidateParent
|
|
3839
3868
|
});
|
|
@@ -3844,7 +3873,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
3844
3873
|
}
|
|
3845
3874
|
}
|
|
3846
3875
|
} catch (err) {
|
|
3847
|
-
|
|
3876
|
+
logger4.debug("[SelectorDerivation] Row-anchor strategy error", {
|
|
3848
3877
|
error: err instanceof Error ? err.message : String(err)
|
|
3849
3878
|
});
|
|
3850
3879
|
}
|
|
@@ -3937,7 +3966,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
3937
3966
|
if (resolved) {
|
|
3938
3967
|
const isSame = await isSameDOMElement(page, originalLocator, resolved, timeoutMs);
|
|
3939
3968
|
if (!isSame) {
|
|
3940
|
-
|
|
3969
|
+
logger4.debug(
|
|
3941
3970
|
"[SelectorDerivation] Parent-scoped selector resolved to wrong element, skipping",
|
|
3942
3971
|
{
|
|
3943
3972
|
selectorType,
|
|
@@ -3946,7 +3975,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
3946
3975
|
);
|
|
3947
3976
|
continue;
|
|
3948
3977
|
}
|
|
3949
|
-
|
|
3978
|
+
logger4.debug("[SelectorDerivation] Found unique parent via simple scoping", {
|
|
3950
3979
|
selectorType,
|
|
3951
3980
|
parentContext: candidateParent
|
|
3952
3981
|
});
|
|
@@ -3958,7 +3987,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
3958
3987
|
}
|
|
3959
3988
|
}
|
|
3960
3989
|
} catch (err) {
|
|
3961
|
-
|
|
3990
|
+
logger4.debug("[SelectorDerivation] Error in simple parent scoping", {
|
|
3962
3991
|
error: err instanceof Error ? err.message : String(err)
|
|
3963
3992
|
});
|
|
3964
3993
|
}
|
|
@@ -4079,7 +4108,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
4079
4108
|
}
|
|
4080
4109
|
const targetEl = elementAncestries.find((e) => e.isTarget);
|
|
4081
4110
|
if (!targetEl) {
|
|
4082
|
-
|
|
4111
|
+
logger4.warn("[SelectorDerivation] Target not found by DOM identity in ancestry search");
|
|
4083
4112
|
return null;
|
|
4084
4113
|
}
|
|
4085
4114
|
for (let depth = 0; depth < maxParentDepth; depth++) {
|
|
@@ -4098,7 +4127,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
4098
4127
|
try {
|
|
4099
4128
|
const resolved = await resolveElement(page, strategyWithChain, timeoutMs, { mode: "verify" });
|
|
4100
4129
|
if (resolved) {
|
|
4101
|
-
|
|
4130
|
+
logger4.debug("[SelectorDerivation] Found unique parent chain via recursive search", {
|
|
4102
4131
|
depth,
|
|
4103
4132
|
parentChain
|
|
4104
4133
|
});
|
|
@@ -4108,7 +4137,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
4108
4137
|
continue;
|
|
4109
4138
|
}
|
|
4110
4139
|
}
|
|
4111
|
-
|
|
4140
|
+
logger4.warn("[SelectorDerivation] No unique parent found, using matchIndex fallback", {
|
|
4112
4141
|
targetIndex: targetEl.index,
|
|
4113
4142
|
matchCount: count
|
|
4114
4143
|
});
|
|
@@ -4117,7 +4146,7 @@ async function discoverParentContext(page, selectors, selectorType, originalLoca
|
|
|
4117
4146
|
};
|
|
4118
4147
|
}
|
|
4119
4148
|
async function probeChildIconCSS(page, originalLocator, role) {
|
|
4120
|
-
const
|
|
4149
|
+
const logger4 = getLogger2();
|
|
4121
4150
|
const iconAttr = await originalLocator.evaluate((el) => {
|
|
4122
4151
|
const svg = el.querySelector("svg[data-icon]");
|
|
4123
4152
|
return svg?.getAttribute("data-icon") ?? null;
|
|
@@ -4127,7 +4156,7 @@ async function probeChildIconCSS(page, originalLocator, role) {
|
|
|
4127
4156
|
try {
|
|
4128
4157
|
const count = await page.locator(baseSelector).count();
|
|
4129
4158
|
if (count === 1) {
|
|
4130
|
-
|
|
4159
|
+
logger4.debug("[SelectorDerivation] probeChildIconCSS found unique selector", {
|
|
4131
4160
|
css: baseSelector
|
|
4132
4161
|
});
|
|
4133
4162
|
return baseSelector;
|
|
@@ -4141,7 +4170,7 @@ async function probeChildIconCSS(page, originalLocator, role) {
|
|
|
4141
4170
|
const hasMarker = await matches.nth(i).evaluate((el, attr) => el.hasAttribute(attr), MARKER);
|
|
4142
4171
|
if (hasMarker) {
|
|
4143
4172
|
const nthSelector = `${baseSelector} >> nth=${i}`;
|
|
4144
|
-
|
|
4173
|
+
logger4.debug("[SelectorDerivation] probeChildIconCSS disambiguated via nth", {
|
|
4145
4174
|
css: nthSelector,
|
|
4146
4175
|
matchCount: count,
|
|
4147
4176
|
index: i
|
|
@@ -4154,7 +4183,7 @@ async function probeChildIconCSS(page, originalLocator, role) {
|
|
|
4154
4183
|
});
|
|
4155
4184
|
}
|
|
4156
4185
|
}
|
|
4157
|
-
|
|
4186
|
+
logger4.debug("[SelectorDerivation] probeChildIconCSS could not disambiguate", {
|
|
4158
4187
|
css: baseSelector,
|
|
4159
4188
|
count
|
|
4160
4189
|
});
|
|
@@ -4164,7 +4193,7 @@ async function probeChildIconCSS(page, originalLocator, role) {
|
|
|
4164
4193
|
}
|
|
4165
4194
|
}
|
|
4166
4195
|
async function probeElementIdCSS(page, originalLocator) {
|
|
4167
|
-
const
|
|
4196
|
+
const logger4 = getLogger2();
|
|
4168
4197
|
const elementId = await originalLocator.evaluate((el) => {
|
|
4169
4198
|
if (el.id) return el.id;
|
|
4170
4199
|
const child = el.querySelector("[id]");
|
|
@@ -4175,7 +4204,7 @@ async function probeElementIdCSS(page, originalLocator) {
|
|
|
4175
4204
|
try {
|
|
4176
4205
|
const count = await page.locator(baseSelector).count();
|
|
4177
4206
|
if (count === 1) {
|
|
4178
|
-
|
|
4207
|
+
logger4.debug("[SelectorDerivation] probeElementIdCSS found unique selector", {
|
|
4179
4208
|
css: baseSelector
|
|
4180
4209
|
});
|
|
4181
4210
|
return baseSelector;
|
|
@@ -4198,7 +4227,7 @@ async function probeElementIdCSS(page, originalLocator) {
|
|
|
4198
4227
|
}
|
|
4199
4228
|
}
|
|
4200
4229
|
if (visibleCount === 1 && targetIsOnlyVisible) {
|
|
4201
|
-
|
|
4230
|
+
logger4.debug("[SelectorDerivation] probeElementIdCSS: single visible among duplicates", {
|
|
4202
4231
|
css: baseSelector,
|
|
4203
4232
|
matchCount: count
|
|
4204
4233
|
});
|
|
@@ -4212,7 +4241,7 @@ async function probeElementIdCSS(page, originalLocator) {
|
|
|
4212
4241
|
const hasMarker = await matches.nth(i).evaluate((el, attr) => el.hasAttribute(attr), MARKER);
|
|
4213
4242
|
if (hasMarker) {
|
|
4214
4243
|
const nthSelector = `${baseSelector} >> nth=${i}`;
|
|
4215
|
-
|
|
4244
|
+
logger4.debug("[SelectorDerivation] probeElementIdCSS disambiguated via nth", {
|
|
4216
4245
|
css: nthSelector,
|
|
4217
4246
|
matchCount: count,
|
|
4218
4247
|
index: i
|
|
@@ -4225,7 +4254,7 @@ async function probeElementIdCSS(page, originalLocator) {
|
|
|
4225
4254
|
});
|
|
4226
4255
|
}
|
|
4227
4256
|
}
|
|
4228
|
-
|
|
4257
|
+
logger4.debug("[SelectorDerivation] probeElementIdCSS could not disambiguate", {
|
|
4229
4258
|
css: baseSelector,
|
|
4230
4259
|
count
|
|
4231
4260
|
});
|
|
@@ -4235,14 +4264,14 @@ async function probeElementIdCSS(page, originalLocator) {
|
|
|
4235
4264
|
}
|
|
4236
4265
|
}
|
|
4237
4266
|
async function probeTitleCSS(page, originalLocator) {
|
|
4238
|
-
const
|
|
4267
|
+
const logger4 = getLogger2();
|
|
4239
4268
|
const titleAttr = await originalLocator.evaluate((el) => el.getAttribute("title")).catch(() => null);
|
|
4240
4269
|
if (!titleAttr) return void 0;
|
|
4241
4270
|
const baseSelector = `[title="${titleAttr}"]`;
|
|
4242
4271
|
try {
|
|
4243
4272
|
const count = await page.locator(baseSelector).count();
|
|
4244
4273
|
if (count === 1) {
|
|
4245
|
-
|
|
4274
|
+
logger4.debug("[SelectorDerivation] probeTitleCSS found unique selector", {
|
|
4246
4275
|
css: baseSelector
|
|
4247
4276
|
});
|
|
4248
4277
|
return baseSelector;
|
|
@@ -4256,7 +4285,7 @@ async function probeTitleCSS(page, originalLocator) {
|
|
|
4256
4285
|
const hasMarker = await matches.nth(i).evaluate((el, attr) => el.hasAttribute(attr), MARKER);
|
|
4257
4286
|
if (hasMarker) {
|
|
4258
4287
|
const nthSelector = `${baseSelector} >> nth=${i}`;
|
|
4259
|
-
|
|
4288
|
+
logger4.debug("[SelectorDerivation] probeTitleCSS disambiguated via nth", {
|
|
4260
4289
|
css: nthSelector,
|
|
4261
4290
|
matchCount: count,
|
|
4262
4291
|
index: i
|
|
@@ -4269,7 +4298,7 @@ async function probeTitleCSS(page, originalLocator) {
|
|
|
4269
4298
|
});
|
|
4270
4299
|
}
|
|
4271
4300
|
}
|
|
4272
|
-
|
|
4301
|
+
logger4.debug("[SelectorDerivation] probeTitleCSS could not disambiguate", {
|
|
4273
4302
|
css: baseSelector,
|
|
4274
4303
|
count
|
|
4275
4304
|
});
|
|
@@ -4375,7 +4404,7 @@ async function probeAncestorRowIndex(elementLocator, timeoutMs = 3e3) {
|
|
|
4375
4404
|
}
|
|
4376
4405
|
async function verifySingleSelector(page, selectors, selectorType, originalLocator, options) {
|
|
4377
4406
|
const { timeoutMs } = options;
|
|
4378
|
-
const
|
|
4407
|
+
const logger4 = getLogger2();
|
|
4379
4408
|
const result = {
|
|
4380
4409
|
selectorType,
|
|
4381
4410
|
verified: false,
|
|
@@ -4395,11 +4424,11 @@ async function verifySingleSelector(page, selectors, selectorType, originalLocat
|
|
|
4395
4424
|
result.verified = true;
|
|
4396
4425
|
return result;
|
|
4397
4426
|
}
|
|
4398
|
-
|
|
4427
|
+
logger4.debug("[SelectorDerivation] Initial resolution failed, trying parent disambiguation", {
|
|
4399
4428
|
selectorType
|
|
4400
4429
|
});
|
|
4401
4430
|
if (selectors.itemIndex !== void 0 || selectors.rowIndex !== void 0) {
|
|
4402
|
-
|
|
4431
|
+
logger4.debug("[SelectorDerivation] Data attributes present but did not disambiguate", {
|
|
4403
4432
|
selectorType,
|
|
4404
4433
|
itemIndex: selectors.itemIndex,
|
|
4405
4434
|
rowIndex: selectors.rowIndex
|
|
@@ -4552,9 +4581,9 @@ var DYNAMIC_TEXT_MIN_RATIO = 0.4;
|
|
|
4552
4581
|
var DYNAMIC_TEXT_DISTINCTIVE_LENGTH = 8;
|
|
4553
4582
|
function buildDynamicValueEntries(variableValues) {
|
|
4554
4583
|
const entries = [];
|
|
4555
|
-
for (const [
|
|
4584
|
+
for (const [key2, value] of Object.entries(variableValues)) {
|
|
4556
4585
|
if (typeof value !== "string" || value.length < DYNAMIC_TEXT_MIN_LENGTH) continue;
|
|
4557
|
-
entries.push({ source: "inputValue", key, value });
|
|
4586
|
+
entries.push({ source: "inputValue", key: key2, value });
|
|
4558
4587
|
}
|
|
4559
4588
|
entries.sort((a, b) => b.value.length - a.value.length);
|
|
4560
4589
|
return entries;
|
|
@@ -4709,9 +4738,9 @@ function hydrateDynamicSelectors(selectors, variableValues) {
|
|
|
4709
4738
|
}
|
|
4710
4739
|
const dynamicText = hydrated.dynamicText;
|
|
4711
4740
|
if (!dynamicText) return hydrated;
|
|
4712
|
-
const { key, originalText } = dynamicText;
|
|
4741
|
+
const { key: key2, originalText } = dynamicText;
|
|
4713
4742
|
selectors = hydrated;
|
|
4714
|
-
const currentValue = variableValues[
|
|
4743
|
+
const currentValue = variableValues[key2];
|
|
4715
4744
|
if (!currentValue || currentValue === originalText) {
|
|
4716
4745
|
return selectors;
|
|
4717
4746
|
}
|
|
@@ -4720,7 +4749,7 @@ function hydrateDynamicSelectors(selectors, variableValues) {
|
|
|
4720
4749
|
getLogger2().warn(
|
|
4721
4750
|
"[SelectorDerivation] Full-field replacement triggered due to stale surrounding text",
|
|
4722
4751
|
{
|
|
4723
|
-
key,
|
|
4752
|
+
key: key2,
|
|
4724
4753
|
originalText,
|
|
4725
4754
|
currentValue,
|
|
4726
4755
|
roleName: selectors.role?.name,
|
|
@@ -4736,8 +4765,8 @@ function hydrateDynamicSelectors(selectors, variableValues) {
|
|
|
4736
4765
|
return nextSelectors;
|
|
4737
4766
|
}
|
|
4738
4767
|
function hydratePlaywrightLocatorVariables(locator, variableValues) {
|
|
4739
|
-
return locator.replace(/\{\{var\.([a-zA-Z0-9_]+)\}\}/g, (match,
|
|
4740
|
-
const value = variableValues[
|
|
4768
|
+
return locator.replace(/\{\{var\.([a-zA-Z0-9_]+)\}\}/g, (match, key2) => {
|
|
4769
|
+
const value = variableValues[key2];
|
|
4741
4770
|
if (value === void 0) return match;
|
|
4742
4771
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
4743
4772
|
});
|
|
@@ -4827,9 +4856,9 @@ var escapeRegex3 = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
|
4827
4856
|
var STRING_LITERAL = /'(?:\\.|[^'\\])*'|"(?:\\.|[^"\\])*"/g;
|
|
4828
4857
|
function replaceVariableValuesInString(input, sortedEntries) {
|
|
4829
4858
|
let out = input;
|
|
4830
|
-
for (const [
|
|
4859
|
+
for (const [key2, value] of sortedEntries) {
|
|
4831
4860
|
if (!value || out.indexOf(value) === -1) continue;
|
|
4832
|
-
out = out.replace(new RegExp(escapeRegex3(value), "g"), `$var.${
|
|
4861
|
+
out = out.replace(new RegExp(escapeRegex3(value), "g"), `$var.${key2}`);
|
|
4833
4862
|
}
|
|
4834
4863
|
return out;
|
|
4835
4864
|
}
|
|
@@ -4846,21 +4875,21 @@ function endsWithOddBackslashes(s) {
|
|
|
4846
4875
|
return count % 2 === 1;
|
|
4847
4876
|
}
|
|
4848
4877
|
function rewriteStringLiteralInner(inner, quote, sortedEntries) {
|
|
4849
|
-
for (const [
|
|
4878
|
+
for (const [key2, value] of sortedEntries) {
|
|
4850
4879
|
if (!value || inner.indexOf(value) === -1) continue;
|
|
4851
|
-
if (inner === value) return `$var.${
|
|
4880
|
+
if (inner === value) return `$var.${key2}`;
|
|
4852
4881
|
const parts = inner.split(value);
|
|
4853
4882
|
if (parts.some((p) => p.length > 0 && endsWithOddBackslashes(p))) continue;
|
|
4854
4883
|
const pieces = [];
|
|
4855
4884
|
for (let i = 0; i < parts.length; i++) {
|
|
4856
4885
|
const segment = parts[i];
|
|
4857
4886
|
if (segment.length > 0) pieces.push(`${quote}${segment}${quote}`);
|
|
4858
|
-
if (i < parts.length - 1) pieces.push(`$var.${
|
|
4887
|
+
if (i < parts.length - 1) pieces.push(`$var.${key2}`);
|
|
4859
4888
|
}
|
|
4860
4889
|
const rebuilt = pieces.join(" + ");
|
|
4861
4890
|
return replaceVariableValuesInJsExpression(
|
|
4862
4891
|
rebuilt,
|
|
4863
|
-
sortedEntries.filter(([k]) => k !==
|
|
4892
|
+
sortedEntries.filter(([k]) => k !== key2)
|
|
4864
4893
|
);
|
|
4865
4894
|
}
|
|
4866
4895
|
return `${quote}${inner}${quote}`;
|
|
@@ -5103,7 +5132,7 @@ var HeadlessDomSession = class {
|
|
|
5103
5132
|
|
|
5104
5133
|
// ../workflow-cache/src/optimizer/trace-node-segmenter.ts
|
|
5105
5134
|
var STEP_GROUP = /^Step (\d+): (.*)$/;
|
|
5106
|
-
var CACHE_REPLAY_GROUP = /^Cache Replay
|
|
5135
|
+
var CACHE_REPLAY_GROUP = /^Cache Replay(?: (\d+))?: (.*)$/;
|
|
5107
5136
|
var INTERNAL_GROUP_PREFIX = "Canary Internal:";
|
|
5108
5137
|
function segmentTraceByNode(groups, actions) {
|
|
5109
5138
|
const nodeGroups = groups.filter(
|
|
@@ -5114,10 +5143,11 @@ function segmentTraceByNode(groups, actions) {
|
|
|
5114
5143
|
const stepMatch = STEP_GROUP.exec(g.name);
|
|
5115
5144
|
const replayMatch = CACHE_REPLAY_GROUP.exec(g.name);
|
|
5116
5145
|
const effectiveEnd = g.endTime ?? sorted[idx + 1]?.startTime;
|
|
5146
|
+
const stepNumberRaw = stepMatch ? stepMatch[1] : replayMatch?.[1];
|
|
5117
5147
|
return {
|
|
5118
5148
|
kind: stepMatch ? "agent-step" : "cache-replay",
|
|
5119
|
-
stepNumber:
|
|
5120
|
-
label: stepMatch ? stepMatch[2] : replayMatch[
|
|
5149
|
+
stepNumber: stepNumberRaw !== void 0 ? Number(stepNumberRaw) : void 0,
|
|
5150
|
+
label: stepMatch ? stepMatch[2] : replayMatch[2],
|
|
5121
5151
|
groupCallId: g.callId,
|
|
5122
5152
|
startTime: g.startTime,
|
|
5123
5153
|
endTime: effectiveEnd,
|
|
@@ -5150,10 +5180,28 @@ function segmentTraceByNode(groups, actions) {
|
|
|
5150
5180
|
}
|
|
5151
5181
|
return segments;
|
|
5152
5182
|
}
|
|
5183
|
+
function resolveSegmentNodeIds(segments, steps) {
|
|
5184
|
+
let cursor = 0;
|
|
5185
|
+
return segments.map((segment) => {
|
|
5186
|
+
if (segment.stepNumber !== void 0) {
|
|
5187
|
+
const idx = segment.stepNumber - 1;
|
|
5188
|
+
cursor = Math.max(cursor, idx + 1);
|
|
5189
|
+
return steps[idx]?.nodeId ?? null;
|
|
5190
|
+
}
|
|
5191
|
+
for (let j = cursor; j < steps.length; j++) {
|
|
5192
|
+
if (steps[j].label === segment.label) {
|
|
5193
|
+
cursor = j + 1;
|
|
5194
|
+
return steps[j].nodeId;
|
|
5195
|
+
}
|
|
5196
|
+
}
|
|
5197
|
+
return null;
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5153
5200
|
|
|
5154
5201
|
// ../workflow-cache/src/optimizer/substrate-materializer.ts
|
|
5155
5202
|
import { mkdir, writeFile } from "fs/promises";
|
|
5156
5203
|
import path from "path";
|
|
5204
|
+
import { pathToFileURL } from "url";
|
|
5157
5205
|
var logger2 = createLogger({ module: "SubstrateMaterializer" });
|
|
5158
5206
|
var SubstrateMaterializer = class {
|
|
5159
5207
|
constructor(opts) {
|
|
@@ -5165,22 +5213,35 @@ var SubstrateMaterializer = class {
|
|
|
5165
5213
|
cache = /* @__PURE__ */ new Map();
|
|
5166
5214
|
session;
|
|
5167
5215
|
ownsSession;
|
|
5216
|
+
/** Parsed trace actions in `actions.jsonl` order — lazy, parsed once. */
|
|
5217
|
+
allActions = null;
|
|
5168
5218
|
/**
|
|
5169
5219
|
* Reconstruct one action's snapshot and capture substrate-v2 over it.
|
|
5170
5220
|
* `phase: 'before'` is the page state the action targeted (locator input);
|
|
5171
5221
|
* `'after'` is its result (the next action's context).
|
|
5222
|
+
*
|
|
5223
|
+
* `actionIndex` is the action's position in `parseTraceActions` order — the
|
|
5224
|
+
* SAME index space as the workspace's `browser/actions.jsonl` and
|
|
5225
|
+
* `optimizer/segments.json` actionIndices. The mutation-filtered index the
|
|
5226
|
+
* snapshot reconstructor uses internally is remapped here; observation
|
|
5227
|
+
* actions (screenshots) are rejected with a self-correcting error.
|
|
5172
5228
|
*/
|
|
5173
5229
|
async materialize(actionIndex, phase = "before") {
|
|
5174
|
-
const
|
|
5175
|
-
const hit = this.cache.get(
|
|
5230
|
+
const key2 = `${actionIndex}:${phase}`;
|
|
5231
|
+
const hit = this.cache.get(key2);
|
|
5176
5232
|
if (hit) return hit;
|
|
5233
|
+
this.allActions ??= parseTraceActions(this.opts.traceZipPath);
|
|
5234
|
+
const resolved = toMutationIndex(this.allActions, actionIndex);
|
|
5235
|
+
if (!resolved.ok) {
|
|
5236
|
+
throw new Error(resolved.reason);
|
|
5237
|
+
}
|
|
5177
5238
|
const results = await reconstructSnapshots({
|
|
5178
5239
|
traceZipPath: this.opts.traceZipPath,
|
|
5179
5240
|
includeScreenshots: false,
|
|
5180
5241
|
includeHtml: true,
|
|
5181
5242
|
filter: phase,
|
|
5182
5243
|
raw: false,
|
|
5183
|
-
actionIndex
|
|
5244
|
+
actionIndex: resolved.mutationIndex
|
|
5184
5245
|
});
|
|
5185
5246
|
const snapshot = results.find((r) => r.phase === phase && r.html);
|
|
5186
5247
|
if (!snapshot?.html) {
|
|
@@ -5189,14 +5250,14 @@ var SubstrateMaterializer = class {
|
|
|
5189
5250
|
);
|
|
5190
5251
|
}
|
|
5191
5252
|
await mkdir(this.opts.outDir, { recursive: true });
|
|
5192
|
-
const domPath = path.
|
|
5253
|
+
const domPath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.dom.html`);
|
|
5193
5254
|
await writeFile(domPath, snapshot.html, "utf-8");
|
|
5194
5255
|
const page = await this.session.page();
|
|
5195
5256
|
try {
|
|
5196
|
-
await page.goto(
|
|
5257
|
+
await page.goto(pathToFileURL(domPath).href, { waitUntil: "load" });
|
|
5197
5258
|
await waitForTraceDomHydration(page);
|
|
5198
5259
|
const substrateYaml = await captureSubstrateV2(page, this.opts.logger ?? logger2);
|
|
5199
|
-
const substratePath = path.
|
|
5260
|
+
const substratePath = path.resolve(this.opts.outDir, `${actionIndex}.${phase}.substrate.v2.yaml`);
|
|
5200
5261
|
await writeFile(substratePath, substrateYaml, "utf-8");
|
|
5201
5262
|
const out = {
|
|
5202
5263
|
substrateYaml,
|
|
@@ -5205,7 +5266,7 @@ var SubstrateMaterializer = class {
|
|
|
5205
5266
|
actionIndex,
|
|
5206
5267
|
phase
|
|
5207
5268
|
};
|
|
5208
|
-
this.cache.set(
|
|
5269
|
+
this.cache.set(key2, out);
|
|
5209
5270
|
return out;
|
|
5210
5271
|
} finally {
|
|
5211
5272
|
await page.close().catch(() => void 0);
|
|
@@ -5224,6 +5285,8 @@ async function waitForTraceDomHydration(page) {
|
|
|
5224
5285
|
}
|
|
5225
5286
|
|
|
5226
5287
|
// ../workflow-cache/src/optimizer/locator-verifier.ts
|
|
5288
|
+
import path2 from "path";
|
|
5289
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
5227
5290
|
var RESOLVE_TIMEOUT_MS2 = 5e3;
|
|
5228
5291
|
function identifyingTokens(strategy) {
|
|
5229
5292
|
const tokens = [];
|
|
@@ -5259,7 +5322,7 @@ var LocatorVerifier = class {
|
|
|
5259
5322
|
const tokenPass = classifyStrategyTokens(opts.strategy);
|
|
5260
5323
|
const page = await this.session.page();
|
|
5261
5324
|
try {
|
|
5262
|
-
await page.goto(
|
|
5325
|
+
await page.goto(pathToFileURL2(path2.resolve(opts.domPath)).href, { waitUntil: "load" });
|
|
5263
5326
|
await waitForTraceDomHydration(page);
|
|
5264
5327
|
await page.ariaSnapshot({ mode: "ai" });
|
|
5265
5328
|
const truth = page.locator(`aria-ref=${opts.targetRef}`);
|
|
@@ -5317,6 +5380,148 @@ var LocatorVerifier = class {
|
|
|
5317
5380
|
}
|
|
5318
5381
|
};
|
|
5319
5382
|
|
|
5383
|
+
// ../workflow-cache/src/optimizer/augmentor-verifier.ts
|
|
5384
|
+
import path3 from "path";
|
|
5385
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
5386
|
+
var logger3 = createLogger({ module: "AugmentorVerifier" });
|
|
5387
|
+
function flatten2(roots) {
|
|
5388
|
+
const out = [];
|
|
5389
|
+
const walk = (n) => {
|
|
5390
|
+
out.push(n);
|
|
5391
|
+
for (const c of n.children) walk(c);
|
|
5392
|
+
};
|
|
5393
|
+
for (const r of roots) walk(r);
|
|
5394
|
+
return out;
|
|
5395
|
+
}
|
|
5396
|
+
var key = (role, name) => `${role}\0${name ?? ""}`;
|
|
5397
|
+
var AugmentorVerifier = class {
|
|
5398
|
+
session;
|
|
5399
|
+
ownsSession;
|
|
5400
|
+
constructor(opts) {
|
|
5401
|
+
this.session = opts?.session ?? new HeadlessDomSession();
|
|
5402
|
+
this.ownsSession = !opts?.session;
|
|
5403
|
+
}
|
|
5404
|
+
async verify(opts) {
|
|
5405
|
+
const { domPath, augmentor } = opts;
|
|
5406
|
+
const issues = [];
|
|
5407
|
+
const page = await this.session.page();
|
|
5408
|
+
try {
|
|
5409
|
+
await page.goto(pathToFileURL3(path3.resolve(domPath)).href, { waitUntil: "load" });
|
|
5410
|
+
await waitForTraceDomHydration(page);
|
|
5411
|
+
const baselineYaml = await captureSubstrateV2(page, logger3);
|
|
5412
|
+
const baselineKeys = new Set(flatten2(parseSnapshot(baselineYaml)).map((e) => key(e.role, e.text)));
|
|
5413
|
+
const pass = await applyCustomAugmentors(page, [augmentor], logger3);
|
|
5414
|
+
const exec = pass.executions[0];
|
|
5415
|
+
const elementsAnnotated = exec?.elementsAnnotated ?? 0;
|
|
5416
|
+
const errored = exec?.errored ?? false;
|
|
5417
|
+
const invariantPassed = exec?.invariantPassed ?? false;
|
|
5418
|
+
const durationMs = exec?.durationMs ?? 0;
|
|
5419
|
+
if (errored) {
|
|
5420
|
+
issues.push(`collector errored in page: ${exec?.errorMessage ?? "unknown"}`);
|
|
5421
|
+
}
|
|
5422
|
+
if (elementsAnnotated === 0) {
|
|
5423
|
+
issues.push("collector annotated 0 elements \u2014 matchSelector found nothing, or every descriptor was rejected");
|
|
5424
|
+
}
|
|
5425
|
+
const augmentedYaml = await captureSubstrateV2(page, logger3);
|
|
5426
|
+
const augmentedEls = flatten2(parseSnapshot(augmentedYaml));
|
|
5427
|
+
const annotatedKeys = new Set(pass.annotations.map((a) => key(a.role, a.name)));
|
|
5428
|
+
const newEls = augmentedEls.filter(
|
|
5429
|
+
(e) => annotatedKeys.has(key(e.role, e.text)) && !baselineKeys.has(key(e.role, e.text))
|
|
5430
|
+
);
|
|
5431
|
+
const baselineAbsent = pass.annotations.length > 0 && newEls.length > 0;
|
|
5432
|
+
if (!baselineAbsent && pass.annotations.length > 0) {
|
|
5433
|
+
issues.push(
|
|
5434
|
+
"annotated (role,name) pairs were already present in the un-augmented snapshot \u2014 this augmentor heals nothing (or the names are not distinctive)"
|
|
5435
|
+
);
|
|
5436
|
+
}
|
|
5437
|
+
const sampleRefs = newEls.slice(0, 8).map((e) => e.ref);
|
|
5438
|
+
const targeting = await Promise.all(
|
|
5439
|
+
sampleRefs.map(async (ref) => {
|
|
5440
|
+
try {
|
|
5441
|
+
const handle = await page.$(`aria-ref=${ref}`);
|
|
5442
|
+
const augId = handle ? await handle.getAttribute("data-augmentor-id").catch(() => null) : null;
|
|
5443
|
+
await handle?.dispose();
|
|
5444
|
+
if (augId !== augmentor.id) {
|
|
5445
|
+
return `ref ${ref} did not resolve to an augmentor-annotated element`;
|
|
5446
|
+
}
|
|
5447
|
+
return null;
|
|
5448
|
+
} catch (err) {
|
|
5449
|
+
return `ref ${ref} could not be resolved: ${err instanceof Error ? err.message : String(err)}`;
|
|
5450
|
+
}
|
|
5451
|
+
})
|
|
5452
|
+
);
|
|
5453
|
+
const targetingIssues = targeting.filter((i) => i !== null);
|
|
5454
|
+
for (const i of targetingIssues) issues.push(i);
|
|
5455
|
+
const refsResolveToTargets = sampleRefs.length > 0 && targetingIssues.length === 0;
|
|
5456
|
+
const cacheCheck = await page.evaluate(() => {
|
|
5457
|
+
const els = Array.from(document.querySelectorAll("[data-augmentor-id]"));
|
|
5458
|
+
let anchorless = 0;
|
|
5459
|
+
const failures = [];
|
|
5460
|
+
els.forEach((el, i) => el.setAttribute("data-aug-verify-idx", String(i)));
|
|
5461
|
+
const anchors = els.map((el) => el.getAttribute("data-augmentor-anchor"));
|
|
5462
|
+
for (const el of els) {
|
|
5463
|
+
el.removeAttribute("role");
|
|
5464
|
+
el.removeAttribute("aria-label");
|
|
5465
|
+
el.removeAttribute("aria-disabled");
|
|
5466
|
+
el.removeAttribute("data-augmentor-id");
|
|
5467
|
+
el.removeAttribute("data-augmentor-anchor");
|
|
5468
|
+
}
|
|
5469
|
+
els.forEach((el, i) => {
|
|
5470
|
+
const anchor = anchors[i];
|
|
5471
|
+
if (!anchor) {
|
|
5472
|
+
anchorless++;
|
|
5473
|
+
return;
|
|
5474
|
+
}
|
|
5475
|
+
if (anchor.length > 500) {
|
|
5476
|
+
failures.push(`stableAnchor #${i} exceeds 500 chars \u2014 too complex to be durable: ${anchor.slice(0, 80)}\u2026`);
|
|
5477
|
+
return;
|
|
5478
|
+
}
|
|
5479
|
+
let matches = [];
|
|
5480
|
+
try {
|
|
5481
|
+
matches = Array.from(document.querySelectorAll(anchor));
|
|
5482
|
+
} catch {
|
|
5483
|
+
failures.push(`stableAnchor #${i} is not a valid selector: ${anchor}`);
|
|
5484
|
+
return;
|
|
5485
|
+
}
|
|
5486
|
+
if (matches.length !== 1) {
|
|
5487
|
+
failures.push(`stableAnchor #${i} matched ${matches.length} elements (want exactly 1): ${anchor}`);
|
|
5488
|
+
} else if (matches[0]?.getAttribute("data-aug-verify-idx") !== String(i)) {
|
|
5489
|
+
failures.push(`stableAnchor #${i} resolved to a different element than its target: ${anchor}`);
|
|
5490
|
+
}
|
|
5491
|
+
});
|
|
5492
|
+
return { anchorless, failures };
|
|
5493
|
+
});
|
|
5494
|
+
for (const f of cacheCheck.failures) issues.push(f);
|
|
5495
|
+
const cacheSafe = cacheCheck.failures.length === 0;
|
|
5496
|
+
if (cacheCheck.anchorless > 0) {
|
|
5497
|
+
issues.push(
|
|
5498
|
+
`${cacheCheck.anchorless} annotated element(s) declared no stableAnchor \u2014 they will be visible to the agent but their locators stay irreducible (workflow-variable / L3 disambiguation)`
|
|
5499
|
+
);
|
|
5500
|
+
}
|
|
5501
|
+
const verified = baselineAbsent && !errored && invariantPassed && elementsAnnotated > 0 && refsResolveToTargets && cacheSafe;
|
|
5502
|
+
return {
|
|
5503
|
+
verified,
|
|
5504
|
+
baselineAbsent,
|
|
5505
|
+
elementsAnnotated,
|
|
5506
|
+
invariantPassed,
|
|
5507
|
+
errored,
|
|
5508
|
+
errorMessage: exec?.errorMessage,
|
|
5509
|
+
sampleRefs,
|
|
5510
|
+
refsResolveToTargets,
|
|
5511
|
+
cacheSafe,
|
|
5512
|
+
anchorlessCount: cacheCheck.anchorless,
|
|
5513
|
+
durationMs,
|
|
5514
|
+
issues
|
|
5515
|
+
};
|
|
5516
|
+
} finally {
|
|
5517
|
+
await page.close().catch(() => void 0);
|
|
5518
|
+
}
|
|
5519
|
+
}
|
|
5520
|
+
async close() {
|
|
5521
|
+
if (this.ownsSession) await this.session.close();
|
|
5522
|
+
}
|
|
5523
|
+
};
|
|
5524
|
+
|
|
5320
5525
|
// ../workflow-cache/src/optimizer/action-synthesizer.ts
|
|
5321
5526
|
var ELEMENT_TARGET_ACTION_TYPES = /* @__PURE__ */ new Set([
|
|
5322
5527
|
"click",
|
|
@@ -5426,8 +5631,11 @@ function buildCacheRecipe(opts) {
|
|
|
5426
5631
|
const bindingKeys = /* @__PURE__ */ new Set();
|
|
5427
5632
|
for (const a of actionsJson) {
|
|
5428
5633
|
if (a.variableKey) bindingKeys.add(`$var.${a.variableKey}`);
|
|
5429
|
-
for (const
|
|
5634
|
+
for (const key2 of Object.values(a.variableBindings ?? {})) bindingKeys.add(`$var.${key2}`);
|
|
5430
5635
|
for (const expr of Object.values(a.macroBindings ?? {})) bindingKeys.add(expr);
|
|
5636
|
+
if (a.actionType === "capture" && typeof a.args?.saveAs === "string" && a.args.saveAs) {
|
|
5637
|
+
bindingKeys.add(`$var.${a.args.saveAs}`);
|
|
5638
|
+
}
|
|
5431
5639
|
}
|
|
5432
5640
|
const missing = opts.requiredTokens.filter((t) => !present.has(t) && !bindingKeys.has(t));
|
|
5433
5641
|
if (missing.length > 0) {
|
|
@@ -5655,13 +5863,13 @@ function resolveMacros(value, ctx) {
|
|
|
5655
5863
|
function resolveMacrosInRecord(values, ctx) {
|
|
5656
5864
|
const resolved = {};
|
|
5657
5865
|
const log = /* @__PURE__ */ new Map();
|
|
5658
|
-
for (const [
|
|
5866
|
+
for (const [key2, value] of Object.entries(values)) {
|
|
5659
5867
|
if (containsMacro(value)) {
|
|
5660
5868
|
const resolvedValue = resolveMacros(value, ctx);
|
|
5661
|
-
resolved[
|
|
5662
|
-
log.set(
|
|
5869
|
+
resolved[key2] = resolvedValue;
|
|
5870
|
+
log.set(key2, { expression: value, resolved: resolvedValue });
|
|
5663
5871
|
} else {
|
|
5664
|
-
resolved[
|
|
5872
|
+
resolved[key2] = value;
|
|
5665
5873
|
}
|
|
5666
5874
|
}
|
|
5667
5875
|
return { resolved, log };
|
|
@@ -5671,12 +5879,13 @@ function resolveNodeInputMacros(inputValues, ctx, workflowState) {
|
|
|
5671
5879
|
const hasMacros = Object.values(inputValues).some((v) => containsMacro(v));
|
|
5672
5880
|
if (!hasMacros) return { resolvedValues: inputValues, macroResolutionLog: void 0 };
|
|
5673
5881
|
const { resolved, log } = resolveMacrosInRecord(inputValues, ctx);
|
|
5674
|
-
for (const [
|
|
5675
|
-
workflowState[`macro:${
|
|
5882
|
+
for (const [key2, { resolved: val }] of log.entries()) {
|
|
5883
|
+
workflowState[`macro:${key2}`] = val;
|
|
5676
5884
|
}
|
|
5677
5885
|
return { resolvedValues: resolved, macroResolutionLog: log };
|
|
5678
5886
|
}
|
|
5679
5887
|
export {
|
|
5888
|
+
AugmentorVerifier,
|
|
5680
5889
|
CACHE_COMPILER_VERSION,
|
|
5681
5890
|
HeadlessDomSession,
|
|
5682
5891
|
LocatorVerifier,
|
|
@@ -5708,6 +5917,7 @@ export {
|
|
|
5708
5917
|
findElementWithAncestors,
|
|
5709
5918
|
findFirstVisibleElement,
|
|
5710
5919
|
generateNodeHash,
|
|
5920
|
+
generateNodeHashV3,
|
|
5711
5921
|
getFrameLocators,
|
|
5712
5922
|
getMacro,
|
|
5713
5923
|
getMacroNames,
|
|
@@ -5732,6 +5942,7 @@ export {
|
|
|
5732
5942
|
resolveMacros,
|
|
5733
5943
|
resolveMacrosInRecord,
|
|
5734
5944
|
resolveNodeInputMacros,
|
|
5945
|
+
resolveSegmentNodeIds,
|
|
5735
5946
|
resolveSpecificIframeSelector,
|
|
5736
5947
|
sanitizeArgsForCache,
|
|
5737
5948
|
segmentTraceByNode,
|
|
@@ -5745,4 +5956,4 @@ export {
|
|
|
5745
5956
|
verifySelectorAgainstRef,
|
|
5746
5957
|
waitForTraceDomHydration
|
|
5747
5958
|
};
|
|
5748
|
-
//# sourceMappingURL=src-
|
|
5959
|
+
//# sourceMappingURL=src-2FK3JHGW.js.map
|