@pushpalsdev/cli 1.1.2 → 1.1.3
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/package.json
CHANGED
|
@@ -92,12 +92,15 @@ export interface BrowserValidationRepairPacket {
|
|
|
92
92
|
stage: string | null;
|
|
93
93
|
selector: string | null;
|
|
94
94
|
expected: string | null;
|
|
95
|
+
failureFocus: string | null;
|
|
95
96
|
digest: string;
|
|
96
97
|
previousDigest: string | null;
|
|
97
98
|
previousStage: string | null;
|
|
98
99
|
previousSelector: string | null;
|
|
99
100
|
previousExpected: string | null;
|
|
101
|
+
previousFailureFocus: string | null;
|
|
100
102
|
progress: "first_failure" | "same_failure" | "new_failure";
|
|
103
|
+
needsDiagnosticProbe: boolean;
|
|
101
104
|
artifacts: string[];
|
|
102
105
|
output: string;
|
|
103
106
|
}
|
|
@@ -1705,9 +1708,48 @@ function extractBrowserValidationStage(text: string): string | null {
|
|
|
1705
1708
|
const value = match?.[1]?.trim();
|
|
1706
1709
|
if (value) return toSingleLine(value, 80);
|
|
1707
1710
|
}
|
|
1711
|
+
const verifiedStages = [...text.matchAll(/\bVerified:\s+([^|\r\n]+)/gi)]
|
|
1712
|
+
.map((match) => match[1]?.trim())
|
|
1713
|
+
.filter((entry): entry is string => Boolean(entry));
|
|
1714
|
+
const lastVerifiedStage = verifiedStages.at(-1);
|
|
1715
|
+
if (lastVerifiedStage) return toSingleLine(lastVerifiedStage, 80);
|
|
1708
1716
|
return null;
|
|
1709
1717
|
}
|
|
1710
1718
|
|
|
1719
|
+
function inferBrowserValidationFailureFocus(params: {
|
|
1720
|
+
stage?: string | null;
|
|
1721
|
+
selector?: string | null;
|
|
1722
|
+
expected?: string | null;
|
|
1723
|
+
text?: string | null;
|
|
1724
|
+
}): string | null {
|
|
1725
|
+
const combined = stripAnsiControlSequences(
|
|
1726
|
+
[params.stage, params.selector, params.expected, params.text].filter(Boolean).join(" "),
|
|
1727
|
+
).toLowerCase();
|
|
1728
|
+
if (!combined.trim()) return null;
|
|
1729
|
+
|
|
1730
|
+
const focusRules: Array<[RegExp, string]> = [
|
|
1731
|
+
[/\b(settings|ui[-\s]?size|scale(?:\s+option)?|settings-ui-|large ui option|medium|compact)\b/i, "settings UI size"],
|
|
1732
|
+
[/\b(shop|skin|ship-option|projectile-option)\b/i, "shop navigation"],
|
|
1733
|
+
[/\b(home|shell|home-screen|home-play|play button|landing)\b/i, "home shell"],
|
|
1734
|
+
[/\b(match[-\s]?entry|start match|game-screen|countdown)\b/i, "match entry"],
|
|
1735
|
+
[/\b(in[-\s]?game|game-control|help-menu|planet|deploy|allocation|resource|decoy|attack|defense|tank)\b/i, "in-game UI"],
|
|
1736
|
+
];
|
|
1737
|
+
for (const [pattern, label] of focusRules) {
|
|
1738
|
+
if (pattern.test(combined)) return label;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
const stableLocatorMatch = combined.match(/\b(?:getbytestid|data-testid|testid)\(?['"`]?([a-z0-9_-]+)/i);
|
|
1742
|
+
if (stableLocatorMatch?.[1]) return `test id ${stableLocatorMatch[1]}`;
|
|
1743
|
+
|
|
1744
|
+
const compact = combined
|
|
1745
|
+
.replace(/[^a-z0-9]+/g, " ")
|
|
1746
|
+
.trim()
|
|
1747
|
+
.split(/\s+/)
|
|
1748
|
+
.slice(0, 5)
|
|
1749
|
+
.join(" ");
|
|
1750
|
+
return compact ? toSingleLine(compact, 80) : null;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1711
1753
|
function extractBalancedLocatorCall(text: string): string | null {
|
|
1712
1754
|
const callPattern = /\b(?:getBy(?:TestId|Role|Text|Label|Placeholder|Title)|locator\.[a-z0-9_]+|page\.[a-z0-9_]+)\(/gi;
|
|
1713
1755
|
let match: RegExpExecArray | null;
|
|
@@ -1918,24 +1960,52 @@ export function buildBrowserValidationRepairPacket(
|
|
|
1918
1960
|
const previousDigest = previousFailureDigests.get(validationCommandKey(run.command)) ?? null;
|
|
1919
1961
|
const recentLogSummary = summarizeRecentBrowserValidationLogs(repo);
|
|
1920
1962
|
const enrichedBrowserContext = [combined, recentLogSummary].filter(Boolean).join("\n");
|
|
1963
|
+
const stage = extractBrowserValidationStage(enrichedBrowserContext);
|
|
1964
|
+
const selector = extractBrowserValidationSelector(enrichedBrowserContext);
|
|
1965
|
+
const expected = extractBrowserValidationExpectedUi(enrichedBrowserContext);
|
|
1966
|
+
const previousStage = previousDigest ? extractBrowserValidationStage(previousDigest) : null;
|
|
1967
|
+
const previousSelector = previousDigest ? extractBrowserValidationSelector(previousDigest) : null;
|
|
1968
|
+
const previousExpected = previousDigest ? extractBrowserValidationExpectedUi(previousDigest) : null;
|
|
1969
|
+
const failureFocus = inferBrowserValidationFailureFocus({
|
|
1970
|
+
stage,
|
|
1971
|
+
selector,
|
|
1972
|
+
expected,
|
|
1973
|
+
text: enrichedBrowserContext,
|
|
1974
|
+
});
|
|
1975
|
+
const previousFailureFocus = previousDigest
|
|
1976
|
+
? inferBrowserValidationFailureFocus({
|
|
1977
|
+
stage: previousStage,
|
|
1978
|
+
selector: previousSelector,
|
|
1979
|
+
expected: previousExpected,
|
|
1980
|
+
text: previousDigest,
|
|
1981
|
+
})
|
|
1982
|
+
: null;
|
|
1921
1983
|
const progress =
|
|
1922
1984
|
previousDigest == null
|
|
1923
1985
|
? "first_failure"
|
|
1924
1986
|
: previousDigest === digest
|
|
1925
1987
|
? "same_failure"
|
|
1926
1988
|
: "new_failure";
|
|
1989
|
+
const needsDiagnosticProbe =
|
|
1990
|
+
failureKind === "assertion" &&
|
|
1991
|
+
Boolean(previousDigest) &&
|
|
1992
|
+
Boolean(failureFocus) &&
|
|
1993
|
+
failureFocus === previousFailureFocus;
|
|
1927
1994
|
return {
|
|
1928
1995
|
command: run.command,
|
|
1929
1996
|
failureKind,
|
|
1930
|
-
stage
|
|
1931
|
-
selector
|
|
1932
|
-
expected
|
|
1997
|
+
stage,
|
|
1998
|
+
selector,
|
|
1999
|
+
expected,
|
|
2000
|
+
failureFocus,
|
|
1933
2001
|
digest,
|
|
1934
2002
|
previousDigest,
|
|
1935
|
-
previousStage
|
|
1936
|
-
previousSelector
|
|
1937
|
-
previousExpected
|
|
2003
|
+
previousStage,
|
|
2004
|
+
previousSelector,
|
|
2005
|
+
previousExpected,
|
|
2006
|
+
previousFailureFocus,
|
|
1938
2007
|
progress,
|
|
2008
|
+
needsDiagnosticProbe,
|
|
1939
2009
|
artifacts: mergeBrowserValidationArtifacts(
|
|
1940
2010
|
extractBrowserValidationArtifacts(combined),
|
|
1941
2011
|
collectRecentBrowserValidationArtifacts(repo),
|
|
@@ -2729,6 +2799,9 @@ export function buildQualityRevisionHint(
|
|
|
2729
2799
|
"- First action: inspect the captured browser output/artifacts and actual rendered UI before editing; do not guess from component names or intended copy.",
|
|
2730
2800
|
);
|
|
2731
2801
|
if (browserRepairPacket.stage) lines.push(`- Stage: ${browserRepairPacket.stage}`);
|
|
2802
|
+
if (browserRepairPacket.failureFocus) {
|
|
2803
|
+
lines.push(`- Failure focus: ${browserRepairPacket.failureFocus}`);
|
|
2804
|
+
}
|
|
2732
2805
|
if (browserRepairPacket.expected) {
|
|
2733
2806
|
lines.push(`- Expected UI: ${browserRepairPacket.expected}`);
|
|
2734
2807
|
}
|
|
@@ -2773,6 +2846,17 @@ export function buildQualityRevisionHint(
|
|
|
2773
2846
|
} else {
|
|
2774
2847
|
lines.push("- Breadcrumb: first captured failure for this command in this revision loop");
|
|
2775
2848
|
}
|
|
2849
|
+
if (browserRepairPacket.needsDiagnosticProbe) {
|
|
2850
|
+
lines.push(
|
|
2851
|
+
"- Convergence mode: diagnostic-first repair. This same browser focus failed in the previous revision, so do not guess another selector or rewrite a different stage.",
|
|
2852
|
+
);
|
|
2853
|
+
lines.push(
|
|
2854
|
+
"- Diagnostic requirement: before editing again, inspect or add a tiny temporary diagnostic around the failing stage that records locator counts, visible textContent, role/ARIA attributes, data-testid values, and a nearby DOM snippet for the candidate nodes.",
|
|
2855
|
+
);
|
|
2856
|
+
lines.push(
|
|
2857
|
+
"- React Native Web note: screenshots can show the intended state while Playwright reads a duplicate or stale rendered node. Prefer one unique selected-state test id or a semantic checked attribute on the stable pressable, then assert locator count and visibility.",
|
|
2858
|
+
);
|
|
2859
|
+
}
|
|
2776
2860
|
if (browserRepairPacket.output) {
|
|
2777
2861
|
lines.push(`- Relevant output: ${browserRepairPacket.output}`);
|
|
2778
2862
|
}
|
|
@@ -2807,9 +2891,15 @@ export function buildQualityRevisionHint(
|
|
|
2807
2891
|
lines.push(
|
|
2808
2892
|
"Executor sandbox rule: if the full browser command cannot run inside this edit turn because local server binding is denied or Expo/Playwright reports ERR_SOCKET_BAD_PORT, listen EPERM, EACCES, or a local port bind/freeport failure before reaching the app, treat that as a Codex executor verification limitation. Do not change app startup, ports, or browser provisioning for that local-only signal unless the ValidationGate failure above is also a startup/setup failure. Use the captured artifacts plus fast checks, then let ValidationGate perform the authoritative browser run.",
|
|
2809
2893
|
);
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2894
|
+
if (browserRepairPacket.needsDiagnosticProbe) {
|
|
2895
|
+
lines.push(
|
|
2896
|
+
`Validation rerun rule: PushPals ValidationGate will rerun "${browserRepairPacket.command}" after the patch, but this is now a repeated browser assertion. If a quick local startup probe shows the browser server can run in this executor, run one targeted "${browserRepairPacket.command}" confirmation after the DOM-backed fix. Do not hand off another unverified selector guess.`,
|
|
2897
|
+
);
|
|
2898
|
+
} else {
|
|
2899
|
+
lines.push(
|
|
2900
|
+
`Validation rerun rule: PushPals ValidationGate will rerun "${browserRepairPacket.command}" after the patch. During a focused browser repair turn, run fast non-browser checks and inspect captured artifacts first; do not run the full browser command from the Codex executor by default. Only run the full browser command for one targeted confirmation if artifacts are missing and a quick local bind/startup probe shows the browser server can actually run in this executor. Otherwise stop after fast checks so ValidationGate gets the clean authoritative signal.`,
|
|
2901
|
+
);
|
|
2902
|
+
}
|
|
2813
2903
|
}
|
|
2814
2904
|
if (reviewFixContext) {
|
|
2815
2905
|
lines.push("Rejected PR retry requirements:");
|