libretto 0.5.0 → 0.5.2
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/README.md +109 -35
- package/dist/cli/cli.js +22 -97
- package/dist/cli/commands/browser.js +86 -59
- package/dist/cli/commands/execution.js +199 -86
- package/dist/cli/commands/init.js +34 -29
- package/dist/cli/commands/logs.js +4 -5
- package/dist/cli/commands/shared.js +30 -29
- package/dist/cli/commands/snapshot.js +26 -39
- package/dist/cli/core/ai-config.js +21 -4
- package/dist/cli/core/api-snapshot-analyzer.js +15 -5
- package/dist/cli/core/browser.js +207 -37
- package/dist/cli/core/context.js +4 -1
- package/dist/cli/core/session-telemetry.js +434 -174
- package/dist/cli/core/session.js +21 -8
- package/dist/cli/core/snapshot-analyzer.js +14 -31
- package/dist/cli/core/snapshot-api-config.js +2 -6
- package/dist/cli/core/telemetry.js +20 -4
- package/dist/cli/framework/simple-cli.js +45 -25
- package/dist/cli/router.js +14 -21
- package/dist/cli/workers/run-integration-runtime.js +24 -5
- package/dist/cli/workers/run-integration-worker-protocol.js +3 -1
- package/dist/cli/workers/run-integration-worker.js +1 -4
- package/dist/index.d.ts +1 -2
- package/dist/index.js +7 -10
- package/dist/runtime/download/download.js +5 -1
- package/dist/runtime/extract/extract.js +11 -2
- package/dist/runtime/network/network.js +8 -1
- package/dist/runtime/recovery/agent.js +6 -2
- package/dist/runtime/recovery/errors.js +3 -1
- package/dist/runtime/recovery/recovery.js +3 -1
- package/dist/shared/condense-dom/condense-dom.js +17 -69
- package/dist/shared/config/config.d.ts +1 -9
- package/dist/shared/config/config.js +0 -18
- package/dist/shared/config/index.d.ts +2 -1
- package/dist/shared/config/index.js +0 -10
- package/dist/shared/debug/pause.js +9 -3
- package/dist/shared/dom-semantics.d.ts +8 -0
- package/dist/shared/dom-semantics.js +69 -0
- package/dist/shared/instrumentation/instrument.js +101 -5
- package/dist/shared/llm/ai-sdk-adapter.js +3 -1
- package/dist/shared/llm/client.js +3 -1
- package/dist/shared/logger/index.js +4 -1
- package/dist/shared/run/api.js +3 -1
- package/dist/shared/run/browser.js +47 -3
- package/dist/shared/state/session-state.d.ts +2 -1
- package/dist/shared/state/session-state.js +5 -2
- package/dist/shared/visualization/ghost-cursor.js +36 -14
- package/dist/shared/visualization/highlight.js +9 -6
- package/dist/shared/workflow/workflow.d.ts +4 -5
- package/dist/shared/workflow/workflow.js +3 -5
- package/package.json +6 -2
- package/scripts/check-skills-sync.mjs +25 -0
- package/scripts/compare-eval-summary.mjs +47 -0
- package/scripts/postinstall.mjs +15 -15
- package/scripts/prepare-release.sh +97 -0
- package/scripts/skills-libretto.mjs +103 -0
- package/scripts/summarize-evals.mjs +135 -0
- package/scripts/sync-skills.mjs +12 -0
- package/skills/libretto/SKILL.md +132 -54
- package/skills/libretto/references/action-logs.md +101 -0
- package/skills/libretto/references/auth-profiles.md +1 -2
- package/skills/libretto/references/code-generation-rules.md +210 -0
- package/skills/libretto/references/configuration-file-reference.md +53 -0
- package/skills/libretto/references/pages-and-page-targeting.md +1 -1
- package/skills/libretto/references/site-security-review.md +143 -0
- package/src/cli/cli.ts +23 -110
- package/src/cli/commands/browser.ts +94 -70
- package/src/cli/commands/execution.ts +233 -102
- package/src/cli/commands/init.ts +37 -33
- package/src/cli/commands/logs.ts +7 -7
- package/src/cli/commands/shared.ts +36 -37
- package/src/cli/commands/snapshot.ts +44 -59
- package/src/cli/core/ai-config.ts +24 -4
- package/src/cli/core/api-snapshot-analyzer.ts +17 -6
- package/src/cli/core/browser.ts +260 -49
- package/src/cli/core/context.ts +7 -2
- package/src/cli/core/session-telemetry.ts +449 -197
- package/src/cli/core/session.ts +21 -7
- package/src/cli/core/snapshot-analyzer.ts +26 -46
- package/src/cli/core/snapshot-api-config.ts +170 -175
- package/src/cli/core/telemetry.ts +39 -4
- package/src/cli/framework/simple-cli.ts +144 -77
- package/src/cli/router.ts +13 -21
- package/src/cli/workers/run-integration-runtime.ts +36 -9
- package/src/cli/workers/run-integration-worker-protocol.ts +2 -0
- package/src/cli/workers/run-integration-worker.ts +1 -4
- package/src/index.ts +73 -66
- package/src/runtime/download/download.ts +62 -58
- package/src/runtime/download/index.ts +5 -5
- package/src/runtime/extract/extract.ts +71 -61
- package/src/runtime/network/index.ts +3 -3
- package/src/runtime/network/network.ts +99 -93
- package/src/runtime/recovery/agent.ts +217 -212
- package/src/runtime/recovery/errors.ts +107 -104
- package/src/runtime/recovery/index.ts +3 -3
- package/src/runtime/recovery/recovery.ts +38 -35
- package/src/shared/condense-dom/condense-dom.ts +27 -82
- package/src/shared/config/config.ts +0 -19
- package/src/shared/config/index.ts +0 -5
- package/src/shared/debug/pause.ts +57 -51
- package/src/shared/dom-semantics.ts +68 -0
- package/src/shared/instrumentation/errors.ts +64 -62
- package/src/shared/instrumentation/index.ts +5 -5
- package/src/shared/instrumentation/instrument.ts +339 -209
- package/src/shared/llm/ai-sdk-adapter.ts +58 -55
- package/src/shared/llm/client.ts +181 -174
- package/src/shared/llm/types.ts +39 -39
- package/src/shared/logger/index.ts +11 -4
- package/src/shared/logger/logger.ts +312 -306
- package/src/shared/logger/sinks.ts +118 -114
- package/src/shared/paths/paths.ts +50 -49
- package/src/shared/paths/repo-root.ts +17 -17
- package/src/shared/run/api.ts +5 -1
- package/src/shared/run/browser.ts +65 -3
- package/src/shared/state/index.ts +9 -9
- package/src/shared/state/session-state.ts +46 -43
- package/src/shared/visualization/ghost-cursor.ts +180 -149
- package/src/shared/visualization/highlight.ts +89 -86
- package/src/shared/visualization/index.ts +13 -13
- package/src/shared/workflow/workflow.ts +19 -25
- package/skills/libretto/references/reverse-engineering-network-requests.md +0 -39
- package/skills/libretto/references/user-action-log.md +0 -31
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const TEST_ATTRIBUTE_NAMES = [
|
|
2
|
+
"data-testid",
|
|
3
|
+
"data-test",
|
|
4
|
+
"data-qa",
|
|
5
|
+
"data-cy",
|
|
6
|
+
] as const;
|
|
7
|
+
|
|
8
|
+
export const TRUSTED_ATTRIBUTE_NAMES = [
|
|
9
|
+
"id",
|
|
10
|
+
"name",
|
|
11
|
+
"for",
|
|
12
|
+
"tabindex",
|
|
13
|
+
"contenteditable",
|
|
14
|
+
"role",
|
|
15
|
+
"title",
|
|
16
|
+
"alt",
|
|
17
|
+
"type",
|
|
18
|
+
"value",
|
|
19
|
+
"placeholder",
|
|
20
|
+
"autocomplete",
|
|
21
|
+
"href",
|
|
22
|
+
"action",
|
|
23
|
+
"method",
|
|
24
|
+
"src",
|
|
25
|
+
] as const;
|
|
26
|
+
|
|
27
|
+
export const INTERACTIVE_TAG_NAMES = [
|
|
28
|
+
"a",
|
|
29
|
+
"button",
|
|
30
|
+
"input",
|
|
31
|
+
"select",
|
|
32
|
+
"textarea",
|
|
33
|
+
"form",
|
|
34
|
+
"details",
|
|
35
|
+
"dialog",
|
|
36
|
+
"label",
|
|
37
|
+
] as const;
|
|
38
|
+
|
|
39
|
+
export const INTERACTIVE_ROLE_NAMES = [
|
|
40
|
+
"button",
|
|
41
|
+
"link",
|
|
42
|
+
"tab",
|
|
43
|
+
"menuitem",
|
|
44
|
+
"checkbox",
|
|
45
|
+
"radio",
|
|
46
|
+
"switch",
|
|
47
|
+
"slider",
|
|
48
|
+
"combobox",
|
|
49
|
+
] as const;
|
|
50
|
+
|
|
51
|
+
export function filterSemanticClasses(value: string): string {
|
|
52
|
+
const classes = value.split(/\s+/).filter(Boolean);
|
|
53
|
+
const kept = classes.filter((cls) => !isObfuscatedClass(cls));
|
|
54
|
+
return kept.join(" ");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function isObfuscatedClass(cls: string): boolean {
|
|
58
|
+
if (cls.length > 80) return true;
|
|
59
|
+
if (/^_?[0-9a-f]{6,}$/i.test(cls)) return true;
|
|
60
|
+
if (/^[a-z]+_[0-9a-f]{4,}$/i.test(cls)) return true;
|
|
61
|
+
if (/^[a-z]{1,2}[0-9]{2,}$/i.test(cls)) return true;
|
|
62
|
+
|
|
63
|
+
const digits = (cls.match(/[0-9]/g) || []).length;
|
|
64
|
+
const letters = (cls.match(/[a-zA-Z]/g) || []).length;
|
|
65
|
+
if (cls.length >= 6 && digits >= letters * 0.5 && digits >= 2) return true;
|
|
66
|
+
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
@@ -8,75 +8,77 @@ import type { Page, Locator } from "playwright";
|
|
|
8
8
|
* Best-effort: if any probe fails, we skip that check silently.
|
|
9
9
|
*/
|
|
10
10
|
export async function enrichTimeoutError(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
err: any,
|
|
12
|
+
locator: Locator,
|
|
13
|
+
page: Page,
|
|
14
14
|
): Promise<void> {
|
|
15
|
-
|
|
15
|
+
const reasons: string[] = [];
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
try {
|
|
18
|
+
const visible = await locator.isVisible().catch(() => null);
|
|
19
|
+
if (visible === false) {
|
|
20
|
+
reasons.push("Element is not visible");
|
|
21
|
+
}
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
// isInViewport is available in modern Playwright but may not exist in older versions
|
|
24
|
+
if (typeof (locator as any).isInViewport === "function") {
|
|
25
|
+
const inViewport = await (locator as any)
|
|
26
|
+
.isInViewport()
|
|
27
|
+
.catch(() => null);
|
|
28
|
+
if (inViewport === false) {
|
|
29
|
+
reasons.push("Element is outside of the viewport");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const enabled = await locator.isEnabled().catch(() => null);
|
|
34
|
+
if (enabled === false) {
|
|
35
|
+
reasons.push("Element is not enabled (disabled)");
|
|
36
|
+
}
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
// If the element appears visible and in viewport, check for intercepting elements
|
|
39
|
+
if (reasons.length === 0) {
|
|
40
|
+
const box = await locator.boundingBox().catch(() => null);
|
|
41
|
+
if (box) {
|
|
42
|
+
const centerX = box.x + box.width / 2;
|
|
43
|
+
const centerY = box.y + box.height / 2;
|
|
42
44
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
const interceptInfo = await page
|
|
46
|
+
.evaluate(
|
|
47
|
+
({ x, y }) => {
|
|
48
|
+
const els = document.elementsFromPoint(x, y);
|
|
49
|
+
if (!els || els.length < 2) return null;
|
|
50
|
+
const topEl = els[0];
|
|
51
|
+
if (!topEl) return null;
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
53
|
+
// Build a brief preview of the intercepting element
|
|
54
|
+
const tag = topEl.tagName.toLowerCase();
|
|
55
|
+
const id = topEl.id ? `#${topEl.id}` : "";
|
|
56
|
+
const cls = topEl.className
|
|
57
|
+
? `.${String(topEl.className).split(/\s+/).slice(0, 2).join(".")}`
|
|
58
|
+
: "";
|
|
59
|
+
const text = (topEl.textContent || "").trim().slice(0, 40);
|
|
60
|
+
return {
|
|
61
|
+
tag,
|
|
62
|
+
preview: `<${tag}${id}${cls}>${text ? ` "${text}"` : ""}`,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
{ x: centerX, y: centerY },
|
|
66
|
+
)
|
|
67
|
+
.catch(() => null);
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
69
|
+
if (interceptInfo) {
|
|
70
|
+
reasons.push(
|
|
71
|
+
`Element may be intercepted by ${interceptInfo.preview}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} catch {
|
|
77
|
+
// All enrichment is best-effort
|
|
78
|
+
}
|
|
77
79
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
80
|
+
if (reasons.length > 0) {
|
|
81
|
+
const enrichment = `\n[libretto diagnostics] ${reasons.join("; ")}`;
|
|
82
|
+
err.message = (err.message || "") + enrichment;
|
|
83
|
+
}
|
|
82
84
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
instrumentPage,
|
|
3
|
+
installInstrumentation,
|
|
4
|
+
instrumentContext,
|
|
5
|
+
type InstrumentationOptions,
|
|
6
|
+
type InstrumentedPage,
|
|
7
7
|
} from "./instrument.js";
|
|
8
8
|
|
|
9
9
|
export { enrichTimeoutError } from "./errors.js";
|