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
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { createLoggerForSession } from "../core/context.js";
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
+
generateSessionName,
|
|
4
5
|
readSessionStateOrThrow,
|
|
5
6
|
validateSessionName
|
|
6
7
|
} from "../core/session.js";
|
|
7
8
|
import {
|
|
8
9
|
SimpleCLI
|
|
9
10
|
} from "../framework/simple-cli.js";
|
|
10
|
-
function
|
|
11
|
-
return z.string().
|
|
12
|
-
try {
|
|
13
|
-
validateSessionName(value);
|
|
14
|
-
} catch (err) {
|
|
15
|
-
ctx.addIssue({
|
|
16
|
-
code: z.ZodIssueCode.custom,
|
|
17
|
-
message: err instanceof Error ? err.message : String(err)
|
|
18
|
-
});
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function sessionOption(help = "Use a named session") {
|
|
23
|
-
return SimpleCLI.option(createSessionSchema(), { help });
|
|
11
|
+
function sessionOption(help = "Session name") {
|
|
12
|
+
return SimpleCLI.option(z.string().optional(), { help });
|
|
24
13
|
}
|
|
25
14
|
function pageOption(help = "Target a specific page id") {
|
|
26
15
|
return SimpleCLI.option(z.string().optional(), { help });
|
|
@@ -28,23 +17,35 @@ function pageOption(help = "Target a specific page id") {
|
|
|
28
17
|
function integerOption(help) {
|
|
29
18
|
return SimpleCLI.option(z.coerce.number().int().optional(), { help });
|
|
30
19
|
}
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
|
|
34
|
-
|
|
20
|
+
function withRequiredSession() {
|
|
21
|
+
return async ({ input, ctx }) => {
|
|
22
|
+
if (!input.session) {
|
|
23
|
+
throw new Error("Missing required option --session.");
|
|
24
|
+
}
|
|
25
|
+
validateSessionName(input.session);
|
|
26
|
+
const logger = createLoggerForSession(input.session);
|
|
27
|
+
return {
|
|
28
|
+
...ctx,
|
|
29
|
+
session: input.session,
|
|
30
|
+
logger,
|
|
31
|
+
sessionState: readSessionStateOrThrow(input.session)
|
|
32
|
+
};
|
|
35
33
|
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return {
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
}
|
|
35
|
+
function withAutoSession() {
|
|
36
|
+
return async ({ input, ctx }) => {
|
|
37
|
+
const session = input.session ?? generateSessionName();
|
|
38
|
+
if (input.session) {
|
|
39
|
+
validateSessionName(input.session);
|
|
40
|
+
}
|
|
41
|
+
const logger = createLoggerForSession(session);
|
|
42
|
+
return { ...ctx, session, logger };
|
|
41
43
|
};
|
|
42
|
-
}
|
|
44
|
+
}
|
|
43
45
|
export {
|
|
44
|
-
createSessionSchema,
|
|
45
46
|
integerOption,
|
|
46
|
-
loadSessionStateMiddleware,
|
|
47
47
|
pageOption,
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
sessionOption,
|
|
49
|
+
withAutoSession,
|
|
50
|
+
withRequiredSession
|
|
50
51
|
};
|
|
@@ -5,16 +5,10 @@ import { getSessionSnapshotRunDir } from "../core/context.js";
|
|
|
5
5
|
import { condenseDom } from "../../shared/condense-dom/condense-dom.js";
|
|
6
6
|
import { readSessionState } from "../core/session.js";
|
|
7
7
|
import { SimpleCLI } from "../framework/simple-cli.js";
|
|
8
|
-
import {
|
|
9
|
-
loadSessionStateMiddleware,
|
|
10
|
-
pageOption,
|
|
11
|
-
resolveSessionMiddleware,
|
|
12
|
-
sessionOption
|
|
13
|
-
} from "./shared.js";
|
|
8
|
+
import { pageOption, sessionOption, withRequiredSession } from "./shared.js";
|
|
14
9
|
import { runApiInterpret } from "../core/api-snapshot-analyzer.js";
|
|
15
10
|
import { readAiConfig } from "../core/ai-config.js";
|
|
16
11
|
import { resolveSnapshotApiModelOrThrow } from "../core/snapshot-api-config.js";
|
|
17
|
-
const DEFAULT_SNAPSHOT_CONTEXT = "No additional user context provided.";
|
|
18
12
|
const FALLBACK_SNAPSHOT_VIEWPORT = { width: 1280, height: 800 };
|
|
19
13
|
function generateSnapshotRunId() {
|
|
20
14
|
return `snapshot-${Date.now()}`;
|
|
@@ -106,6 +100,12 @@ async function captureScreenshot(session, logger, pageId) {
|
|
|
106
100
|
const pngPath = `${snapshotRunDir}/page.png`;
|
|
107
101
|
const htmlPath = `${snapshotRunDir}/page.html`;
|
|
108
102
|
const condensedHtmlPath = `${snapshotRunDir}/page.condensed.html`;
|
|
103
|
+
const RENDER_SETTLE_TIMEOUT_MS = 1e4;
|
|
104
|
+
await Promise.race([
|
|
105
|
+
page.waitForLoadState("networkidle").catch(() => {
|
|
106
|
+
}),
|
|
107
|
+
new Promise((resolve) => setTimeout(resolve, RENDER_SETTLE_TIMEOUT_MS))
|
|
108
|
+
]);
|
|
109
109
|
const restoreViewport = resolveSnapshotViewport(session, logger);
|
|
110
110
|
const viewportMetrics = await readSnapshotViewportMetrics(page);
|
|
111
111
|
logger.info("screenshot-viewport-metrics", {
|
|
@@ -185,17 +185,10 @@ async function captureScreenshot(session, logger, pageId) {
|
|
|
185
185
|
}
|
|
186
186
|
}
|
|
187
187
|
async function runSnapshot(session, logger, pageId, objective, context) {
|
|
188
|
-
const normalizedObjective = objective
|
|
189
|
-
const normalizedContext = context
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
"Couldn't run analysis: --objective is required when providing --context."
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
const configuredAi = normalizedObjective ? readAiConfig() : null;
|
|
196
|
-
if (normalizedObjective) {
|
|
197
|
-
resolveSnapshotApiModelOrThrow(configuredAi);
|
|
198
|
-
}
|
|
188
|
+
const normalizedObjective = objective.trim();
|
|
189
|
+
const normalizedContext = context.trim();
|
|
190
|
+
const configuredAi = readAiConfig();
|
|
191
|
+
resolveSnapshotApiModelOrThrow(configuredAi);
|
|
199
192
|
const { pngPath, htmlPath, condensedHtmlPath } = await captureScreenshot(
|
|
200
193
|
session,
|
|
201
194
|
logger,
|
|
@@ -205,14 +198,10 @@ async function runSnapshot(session, logger, pageId, objective, context) {
|
|
|
205
198
|
console.log(` PNG: ${pngPath}`);
|
|
206
199
|
console.log(` HTML: ${htmlPath}`);
|
|
207
200
|
console.log(` Condensed HTML: ${condensedHtmlPath}`);
|
|
208
|
-
if (!normalizedObjective) {
|
|
209
|
-
console.log("Use --objective flag to analyze snapshots.");
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
201
|
const interpretArgs = {
|
|
213
202
|
objective: normalizedObjective,
|
|
214
203
|
session,
|
|
215
|
-
context: normalizedContext
|
|
204
|
+
context: normalizedContext,
|
|
216
205
|
pngPath,
|
|
217
206
|
htmlPath,
|
|
218
207
|
condensedHtmlPath
|
|
@@ -224,24 +213,22 @@ const snapshotInput = SimpleCLI.input({
|
|
|
224
213
|
named: {
|
|
225
214
|
session: sessionOption(),
|
|
226
215
|
page: pageOption(),
|
|
227
|
-
objective: SimpleCLI.option(z.string()
|
|
228
|
-
context: SimpleCLI.option(z.string()
|
|
216
|
+
objective: SimpleCLI.option(z.string()),
|
|
217
|
+
context: SimpleCLI.option(z.string())
|
|
229
218
|
}
|
|
230
219
|
});
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
});
|
|
243
|
-
}
|
|
220
|
+
const snapshotCommand = SimpleCLI.command({
|
|
221
|
+
description: "Capture PNG + HTML and analyze with --objective and --context"
|
|
222
|
+
}).input(snapshotInput).use(withRequiredSession()).handle(async ({ input, ctx }) => {
|
|
223
|
+
await runSnapshot(
|
|
224
|
+
ctx.session,
|
|
225
|
+
ctx.logger,
|
|
226
|
+
input.page,
|
|
227
|
+
input.objective,
|
|
228
|
+
input.context
|
|
229
|
+
);
|
|
230
|
+
});
|
|
244
231
|
export {
|
|
245
|
-
|
|
232
|
+
snapshotCommand,
|
|
246
233
|
snapshotInput
|
|
247
234
|
};
|
|
@@ -11,10 +11,15 @@ const ViewportConfigSchema = z.object({
|
|
|
11
11
|
width: z.number().int().min(1),
|
|
12
12
|
height: z.number().int().min(1)
|
|
13
13
|
});
|
|
14
|
+
const WindowPositionConfigSchema = z.object({
|
|
15
|
+
x: z.number().int(),
|
|
16
|
+
y: z.number().int()
|
|
17
|
+
});
|
|
14
18
|
const LibrettoConfigSchema = z.object({
|
|
15
19
|
version: z.literal(CURRENT_CONFIG_VERSION),
|
|
16
20
|
ai: AiConfigSchema.optional(),
|
|
17
|
-
viewport: ViewportConfigSchema.optional()
|
|
21
|
+
viewport: ViewportConfigSchema.optional(),
|
|
22
|
+
windowPosition: WindowPositionConfigSchema.optional()
|
|
18
23
|
}).passthrough();
|
|
19
24
|
const DEFAULT_MODELS = {
|
|
20
25
|
openai: "openai/gpt-5.4",
|
|
@@ -26,7 +31,12 @@ const PROVIDER_ALIASES = {
|
|
|
26
31
|
claude: DEFAULT_MODELS.anthropic,
|
|
27
32
|
google: DEFAULT_MODELS.gemini
|
|
28
33
|
};
|
|
29
|
-
const CONFIGURE_PROVIDERS = [
|
|
34
|
+
const CONFIGURE_PROVIDERS = [
|
|
35
|
+
"openai",
|
|
36
|
+
"anthropic",
|
|
37
|
+
"gemini",
|
|
38
|
+
"vertex"
|
|
39
|
+
];
|
|
30
40
|
function formatConfigureProviders(separator = " | ") {
|
|
31
41
|
return CONFIGURE_PROVIDERS.join(separator);
|
|
32
42
|
}
|
|
@@ -44,6 +54,10 @@ function formatExpectedConfigExample() {
|
|
|
44
54
|
viewport: {
|
|
45
55
|
width: 1280,
|
|
46
56
|
height: 800
|
|
57
|
+
},
|
|
58
|
+
windowPosition: {
|
|
59
|
+
x: 1600,
|
|
60
|
+
y: 120
|
|
47
61
|
}
|
|
48
62
|
},
|
|
49
63
|
null,
|
|
@@ -59,7 +73,7 @@ ${detail}` : null,
|
|
|
59
73
|
"Expected config example:",
|
|
60
74
|
formatExpectedConfigExample(),
|
|
61
75
|
"Notes:",
|
|
62
|
-
' - "ai" and "
|
|
76
|
+
' - "ai", "viewport", and "windowPosition" are optional.',
|
|
63
77
|
' - "ai.model" must be a provider/model string like "openai/gpt-5.4" or "anthropic/claude-sonnet-4-6".',
|
|
64
78
|
"Fix the file to match this shape, or delete it and rerun:",
|
|
65
79
|
` npx libretto ai configure ${formatConfigureProviders()}`
|
|
@@ -147,7 +161,9 @@ function runAiConfigure(input, options = {}) {
|
|
|
147
161
|
console.log(
|
|
148
162
|
`No AI config set. Choose a default model: ${configureCommandName} ${formatConfigureProviders()}`
|
|
149
163
|
);
|
|
150
|
-
console.log(
|
|
164
|
+
console.log(
|
|
165
|
+
"Provider credentials still come from your shell or .env file."
|
|
166
|
+
);
|
|
151
167
|
return;
|
|
152
168
|
}
|
|
153
169
|
printAiConfig(config2, configPath);
|
|
@@ -182,6 +198,7 @@ export {
|
|
|
182
198
|
CURRENT_CONFIG_VERSION,
|
|
183
199
|
LibrettoConfigSchema,
|
|
184
200
|
ViewportConfigSchema,
|
|
201
|
+
WindowPositionConfigSchema,
|
|
185
202
|
clearAiConfig,
|
|
186
203
|
readAiConfig,
|
|
187
204
|
readLibrettoConfig,
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { createLLMClient } from "../../shared/llm/client.js";
|
|
3
3
|
import {
|
|
4
|
-
formatInterpretationOutput,
|
|
5
4
|
InterpretResultSchema,
|
|
6
5
|
buildInlinePromptSelection,
|
|
7
6
|
getMimeType,
|
|
8
7
|
readFileAsBase64
|
|
9
8
|
} from "./snapshot-analyzer.js";
|
|
10
9
|
import { readAiConfig } from "./ai-config.js";
|
|
11
|
-
import {
|
|
12
|
-
resolveSnapshotApiModelOrThrow
|
|
13
|
-
} from "./snapshot-api-config.js";
|
|
10
|
+
import { resolveSnapshotApiModelOrThrow } from "./snapshot-api-config.js";
|
|
14
11
|
async function runApiInterpret(args, logger, configuredAi = readAiConfig()) {
|
|
15
12
|
const selection = resolveSnapshotApiModelOrThrow(configuredAi);
|
|
16
13
|
logger.info("api-interpret-start", {
|
|
@@ -67,7 +64,20 @@ async function runApiInterpret(args, logger, configuredAi = readAiConfig()) {
|
|
|
67
64
|
selectorCount: parsed.selectors.length,
|
|
68
65
|
answer: parsed.answer.slice(0, 200)
|
|
69
66
|
});
|
|
70
|
-
console.log(
|
|
67
|
+
console.log("");
|
|
68
|
+
console.log("Analysis:");
|
|
69
|
+
console.log(parsed.answer);
|
|
70
|
+
if (parsed.selectors.length > 0) {
|
|
71
|
+
console.log("");
|
|
72
|
+
console.log("Selectors:");
|
|
73
|
+
parsed.selectors.forEach((selector, index) => {
|
|
74
|
+
console.log(` ${index + 1}. ${selector.label}: ${selector.selector}`);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (parsed.notes?.trim()) {
|
|
78
|
+
console.log("");
|
|
79
|
+
console.log(`Notes: ${parsed.notes.trim()}`);
|
|
80
|
+
}
|
|
71
81
|
}
|
|
72
82
|
export {
|
|
73
83
|
runApiInterpret
|