libretto 0.2.0 → 0.2.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.
Files changed (65) hide show
  1. package/README.md +128 -126
  2. package/dist/cli/cli.js +2 -0
  3. package/dist/cli/commands/browser.js +4 -1
  4. package/dist/cli/commands/execution.js +21 -6
  5. package/dist/cli/commands/logs.js +36 -8
  6. package/dist/cli/commands/snapshot.js +14 -7
  7. package/dist/cli/core/browser.js +89 -253
  8. package/dist/cli/core/session-telemetry.js +491 -0
  9. package/dist/cli/core/telemetry.js +18 -6
  10. package/dist/cli/workers/run-integration-runtime.js +19 -1
  11. package/dist/index.cjs +2 -6
  12. package/dist/index.d.cts +2 -5
  13. package/dist/index.d.ts +2 -5
  14. package/dist/index.js +2 -5
  15. package/dist/runtime/download/download.d.cts +2 -2
  16. package/dist/runtime/download/download.d.ts +2 -2
  17. package/dist/runtime/extract/extract.cjs +2 -1
  18. package/dist/runtime/extract/extract.d.cts +5 -5
  19. package/dist/runtime/extract/extract.d.ts +5 -5
  20. package/dist/runtime/extract/extract.js +2 -1
  21. package/dist/runtime/network/network.d.cts +6 -6
  22. package/dist/runtime/network/network.d.ts +6 -6
  23. package/dist/runtime/recovery/agent.cjs +12 -7
  24. package/dist/runtime/recovery/agent.d.cts +2 -2
  25. package/dist/runtime/recovery/agent.d.ts +2 -2
  26. package/dist/runtime/recovery/agent.js +12 -7
  27. package/dist/runtime/recovery/errors.cjs +8 -6
  28. package/dist/runtime/recovery/errors.d.cts +2 -2
  29. package/dist/runtime/recovery/errors.d.ts +2 -2
  30. package/dist/runtime/recovery/errors.js +8 -6
  31. package/dist/runtime/recovery/recovery.cjs +5 -3
  32. package/dist/runtime/recovery/recovery.d.cts +2 -2
  33. package/dist/runtime/recovery/recovery.d.ts +2 -2
  34. package/dist/runtime/recovery/recovery.js +5 -3
  35. package/dist/shared/instrumentation/instrument.d.cts +2 -2
  36. package/dist/shared/instrumentation/instrument.d.ts +2 -2
  37. package/dist/shared/llm/types.d.cts +5 -5
  38. package/dist/shared/llm/types.d.ts +5 -5
  39. package/dist/shared/logger/index.cjs +2 -0
  40. package/dist/shared/logger/index.d.cts +1 -1
  41. package/dist/shared/logger/index.d.ts +1 -1
  42. package/dist/shared/logger/index.js +2 -1
  43. package/dist/shared/logger/logger.cjs +15 -2
  44. package/dist/shared/logger/logger.d.cts +13 -1
  45. package/dist/shared/logger/logger.d.ts +13 -1
  46. package/dist/shared/logger/logger.js +13 -1
  47. package/dist/shared/state/session-state.d.cts +2 -2
  48. package/dist/shared/state/session-state.d.ts +2 -2
  49. package/package.json +12 -10
  50. package/dist/runtime/step/index.cjs +0 -31
  51. package/dist/runtime/step/index.d.cts +0 -7
  52. package/dist/runtime/step/index.d.ts +0 -7
  53. package/dist/runtime/step/index.js +0 -6
  54. package/dist/runtime/step/runner.cjs +0 -208
  55. package/dist/runtime/step/runner.d.cts +0 -16
  56. package/dist/runtime/step/runner.d.ts +0 -16
  57. package/dist/runtime/step/runner.js +0 -187
  58. package/dist/runtime/step/step.cjs +0 -67
  59. package/dist/runtime/step/step.d.cts +0 -23
  60. package/dist/runtime/step/step.d.ts +0 -23
  61. package/dist/runtime/step/step.js +0 -43
  62. package/dist/runtime/step/types.cjs +0 -16
  63. package/dist/runtime/step/types.d.cts +0 -72
  64. package/dist/runtime/step/types.d.ts +0 -72
  65. package/dist/runtime/step/types.js +0 -0
@@ -1,187 +0,0 @@
1
- import { writeFileSync, mkdirSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { Logger } from "../../shared/logger/logger.js";
4
- import { createFileLogSink, prettyConsoleSink } from "../../shared/logger/sinks.js";
5
- import { isDryRun } from "../../shared/config/config.js";
6
- import { debugPause } from "../../shared/debug/pause.js";
7
- import { attemptWithRecovery } from "../recovery/recovery.js";
8
- import {
9
- ensureLibrettoRunnerLogDir,
10
- getRunnerLogPathForDir
11
- } from "../../shared/paths/paths.js";
12
- function createRunner(config = {}) {
13
- const {
14
- llmClient,
15
- dryRun: dryRunOption,
16
- debug: debugOption,
17
- sessionName = "libretto",
18
- logDir: configuredLogDir
19
- } = config;
20
- const dryRun = dryRunOption ?? isDryRun();
21
- const debug = debugOption ?? false;
22
- const logDir = configuredLogDir ?? ensureLibrettoRunnerLogDir(sessionName);
23
- return {
24
- run: async (page, steps) => {
25
- mkdirSync(logDir, { recursive: true });
26
- const logPath = getRunnerLogPathForDir(logDir);
27
- const logger = new Logger().withSink(createFileLogSink({ filePath: logPath })).withSink(prettyConsoleSink);
28
- const stepHistory = [];
29
- logger.info("runner:start", {
30
- totalSteps: steps.length,
31
- dryRun,
32
- debug,
33
- logDir
34
- });
35
- for (const step of steps) {
36
- const stepLogger = logger.withScope(`step:${step.name}`);
37
- const startTime = Date.now();
38
- if (dryRun && step.options.dryRun !== "execute") {
39
- if (step.options.dryRun === "skip") {
40
- stepLogger.info("skipped (dry-run)");
41
- stepHistory.push({
42
- name: step.name,
43
- status: "skipped",
44
- duration: 0
45
- });
46
- continue;
47
- }
48
- if (step.options.dryRun === "simulate" && step.options.simulate) {
49
- stepLogger.info("simulating (dry-run)");
50
- try {
51
- await step.options.simulate({ logger: stepLogger });
52
- } catch (simError) {
53
- stepLogger.warn("simulate failed", { error: simError });
54
- }
55
- stepHistory.push({
56
- name: step.name,
57
- status: "simulated",
58
- duration: Date.now() - startTime
59
- });
60
- continue;
61
- }
62
- stepLogger.info("skipped (dry-run, no simulate fn)");
63
- stepHistory.push({
64
- name: step.name,
65
- status: "skipped",
66
- duration: 0
67
- });
68
- continue;
69
- }
70
- await captureScreenshot(page, join(logDir, `${step.name}-start.png`), stepLogger);
71
- stepLogger.info("start");
72
- try {
73
- await attemptWithRecovery(
74
- page,
75
- () => step.handler({ page, logger: stepLogger, config: { dryRun, debug, logDir } }),
76
- stepLogger,
77
- llmClient
78
- );
79
- stepHistory.push({
80
- name: step.name,
81
- status: "completed",
82
- duration: Date.now() - startTime
83
- });
84
- stepLogger.info("end", { status: "completed", duration: Date.now() - startTime });
85
- } catch (firstError) {
86
- let recovered = false;
87
- const customRecovery = step.options.recovery ?? {};
88
- for (const [recoveryName, recoveryHandler] of Object.entries(customRecovery)) {
89
- try {
90
- stepLogger.info(`trying custom recovery: ${recoveryName}`);
91
- await recoveryHandler({ page, logger: stepLogger });
92
- await step.handler({ page, logger: stepLogger, config: { dryRun, debug, logDir } });
93
- recovered = true;
94
- stepHistory.push({
95
- name: step.name,
96
- status: "completed",
97
- duration: Date.now() - startTime
98
- });
99
- stepLogger.info("end", {
100
- status: "completed",
101
- recoveredBy: recoveryName,
102
- duration: Date.now() - startTime
103
- });
104
- break;
105
- } catch {
106
- stepLogger.warn(`custom recovery "${recoveryName}" failed`);
107
- }
108
- }
109
- if (!recovered) {
110
- stepHistory.push({
111
- name: step.name,
112
- status: "failed",
113
- duration: Date.now() - startTime
114
- });
115
- const bundle = await generateDebugBundle(
116
- page,
117
- step.name,
118
- firstError,
119
- logDir,
120
- logPath,
121
- stepHistory,
122
- stepLogger
123
- );
124
- stepLogger.info("step:debug-bundle", { path: bundle.bundlePath });
125
- if (debug) {
126
- await debugPause({
127
- page,
128
- session: sessionName
129
- });
130
- }
131
- throw firstError;
132
- }
133
- }
134
- await captureScreenshot(page, join(logDir, `${step.name}-end.png`), stepLogger);
135
- }
136
- logger.info("runner:complete", {
137
- totalSteps: steps.length,
138
- completed: stepHistory.filter((s) => s.status === "completed").length,
139
- skipped: stepHistory.filter((s) => s.status === "skipped").length,
140
- simulated: stepHistory.filter((s) => s.status === "simulated").length
141
- });
142
- await logger.close();
143
- }
144
- };
145
- }
146
- async function captureScreenshot(page, filePath, logger) {
147
- try {
148
- const buffer = await page.screenshot({ fullPage: false, timeout: 5e3 });
149
- writeFileSync(filePath, buffer);
150
- } catch (err) {
151
- logger.warn("Failed to capture screenshot", {
152
- path: filePath,
153
- error: err instanceof Error ? err.message : String(err)
154
- });
155
- }
156
- }
157
- async function generateDebugBundle(page, stepName, error, logDir, logPath, stepHistory, logger) {
158
- const screenshotPath = join(logDir, `${stepName}-error.png`);
159
- const domPath = join(logDir, `${stepName}-error.html`);
160
- const bundlePath = join(logDir, `${stepName}-debug-bundle.json`);
161
- await captureScreenshot(page, screenshotPath, logger);
162
- try {
163
- const html = await page.content();
164
- writeFileSync(domPath, html);
165
- } catch (domErr) {
166
- logger.warn("Failed to capture DOM for debug bundle", {
167
- error: domErr instanceof Error ? domErr.message : String(domErr)
168
- });
169
- }
170
- const pageUrl = page.isClosed() ? "" : page.url();
171
- const bundle = {
172
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
173
- step: stepName,
174
- error: error instanceof Error ? error.message : String(error),
175
- stacktrace: error instanceof Error ? error.stack ?? "" : "",
176
- screenshotPath,
177
- domPath,
178
- logPath,
179
- stepHistory,
180
- pageUrl
181
- };
182
- writeFileSync(bundlePath, JSON.stringify(bundle, null, 2));
183
- return { bundlePath };
184
- }
185
- export {
186
- createRunner
187
- };
@@ -1,67 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var step_exports = {};
20
- __export(step_exports, {
21
- step: () => step
22
- });
23
- module.exports = __toCommonJS(step_exports);
24
- function step(nameOrHandler, handlerOrOptions, maybeOptions) {
25
- let name;
26
- let handler;
27
- let options;
28
- if (typeof nameOrHandler === "string") {
29
- name = nameOrHandler;
30
- handler = handlerOrOptions;
31
- options = maybeOptions ?? {};
32
- } else {
33
- name = `step-${_autoNameCounter++}`;
34
- handler = nameOrHandler;
35
- options = handlerOrOptions ?? {};
36
- }
37
- return {
38
- name,
39
- handler,
40
- options: {
41
- dryRun: options.dryRun ?? "skip",
42
- simulate: options.simulate,
43
- recovery: options.recovery
44
- }
45
- };
46
- }
47
- let _autoNameCounter = 1;
48
- step.extend = function extend(extendOptions) {
49
- return function extendedStep(nameOrHandler, handlerOrOptions, maybeOptions) {
50
- const baseStep = step(nameOrHandler, handlerOrOptions, maybeOptions);
51
- const mergedRecovery = {
52
- ...extendOptions.recovery,
53
- ...baseStep.options.recovery
54
- };
55
- return {
56
- ...baseStep,
57
- options: {
58
- ...baseStep.options,
59
- recovery: mergedRecovery
60
- }
61
- };
62
- };
63
- };
64
- // Annotate the CommonJS export names for ESM import in node:
65
- 0 && (module.exports = {
66
- step
67
- });
@@ -1,23 +0,0 @@
1
- import { StepHandler, StepOptions, Step, RecoveryHandler } from './types.cjs';
2
- import 'playwright';
3
- import '../../shared/logger/logger.cjs';
4
- import '../../shared/llm/types.cjs';
5
- import 'zod';
6
-
7
- /**
8
- * Creates a Step object from a name, handler, and options.
9
- *
10
- * Usage:
11
- * step("login", async ({ page }) => { ... })
12
- * step("login", async ({ page }) => { ... }, { dryRun: "execute" })
13
- * step(async ({ page }) => { ... }) // auto-named
14
- */
15
- declare function step(nameOrHandler: string | StepHandler, handlerOrOptions?: StepHandler | StepOptions, maybeOptions?: StepOptions): Step;
16
- declare namespace step {
17
- var extend: (extendOptions: ExtendOptions) => (nameOrHandler: string | StepHandler, handlerOrOptions?: StepHandler | StepOptions, maybeOptions?: StepOptions) => Step;
18
- }
19
- type ExtendOptions = {
20
- recovery: Record<string, RecoveryHandler>;
21
- };
22
-
23
- export { type ExtendOptions, step };
@@ -1,23 +0,0 @@
1
- import { StepHandler, StepOptions, Step, RecoveryHandler } from './types.js';
2
- import 'playwright';
3
- import '../../shared/logger/logger.js';
4
- import '../../shared/llm/types.js';
5
- import 'zod';
6
-
7
- /**
8
- * Creates a Step object from a name, handler, and options.
9
- *
10
- * Usage:
11
- * step("login", async ({ page }) => { ... })
12
- * step("login", async ({ page }) => { ... }, { dryRun: "execute" })
13
- * step(async ({ page }) => { ... }) // auto-named
14
- */
15
- declare function step(nameOrHandler: string | StepHandler, handlerOrOptions?: StepHandler | StepOptions, maybeOptions?: StepOptions): Step;
16
- declare namespace step {
17
- var extend: (extendOptions: ExtendOptions) => (nameOrHandler: string | StepHandler, handlerOrOptions?: StepHandler | StepOptions, maybeOptions?: StepOptions) => Step;
18
- }
19
- type ExtendOptions = {
20
- recovery: Record<string, RecoveryHandler>;
21
- };
22
-
23
- export { type ExtendOptions, step };
@@ -1,43 +0,0 @@
1
- function step(nameOrHandler, handlerOrOptions, maybeOptions) {
2
- let name;
3
- let handler;
4
- let options;
5
- if (typeof nameOrHandler === "string") {
6
- name = nameOrHandler;
7
- handler = handlerOrOptions;
8
- options = maybeOptions ?? {};
9
- } else {
10
- name = `step-${_autoNameCounter++}`;
11
- handler = nameOrHandler;
12
- options = handlerOrOptions ?? {};
13
- }
14
- return {
15
- name,
16
- handler,
17
- options: {
18
- dryRun: options.dryRun ?? "skip",
19
- simulate: options.simulate,
20
- recovery: options.recovery
21
- }
22
- };
23
- }
24
- let _autoNameCounter = 1;
25
- step.extend = function extend(extendOptions) {
26
- return function extendedStep(nameOrHandler, handlerOrOptions, maybeOptions) {
27
- const baseStep = step(nameOrHandler, handlerOrOptions, maybeOptions);
28
- const mergedRecovery = {
29
- ...extendOptions.recovery,
30
- ...baseStep.options.recovery
31
- };
32
- return {
33
- ...baseStep,
34
- options: {
35
- ...baseStep.options,
36
- recovery: mergedRecovery
37
- }
38
- };
39
- };
40
- };
41
- export {
42
- step
43
- };
@@ -1,16 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __copyProps = (to, from, except, desc) => {
7
- if (from && typeof from === "object" || typeof from === "function") {
8
- for (let key of __getOwnPropNames(from))
9
- if (!__hasOwnProp.call(to, key) && key !== except)
10
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
- }
12
- return to;
13
- };
14
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
- var types_exports = {};
16
- module.exports = __toCommonJS(types_exports);
@@ -1,72 +0,0 @@
1
- import { Page } from 'playwright';
2
- import { LoggerApi } from '../../shared/logger/logger.cjs';
3
- import { LLMClient } from '../../shared/llm/types.cjs';
4
- import 'zod';
5
-
6
- type StepContext = {
7
- page: Page;
8
- logger: LoggerApi;
9
- config: {
10
- dryRun: boolean;
11
- debug: boolean;
12
- logDir: string;
13
- };
14
- };
15
- type RecoveryHandler = (ctx: {
16
- page: Page;
17
- logger: LoggerApi;
18
- }) => Promise<void>;
19
- type StepOptions = {
20
- /**
21
- * Behavior in dry-run mode:
22
- * - "execute": always run, even in dry-run (e.g., login steps)
23
- * - "skip": skip entirely in dry-run
24
- * - "simulate": call the simulate function instead
25
- *
26
- * Defaults to "skip".
27
- */
28
- dryRun?: "execute" | "skip" | "simulate";
29
- /**
30
- * Function to call instead of the handler when dryRun is "simulate".
31
- */
32
- simulate?: (ctx: {
33
- logger: LoggerApi;
34
- }) => Promise<any>;
35
- /**
36
- * Custom recovery handlers keyed by name.
37
- * These run after built-in popup recovery on failure.
38
- */
39
- recovery?: Record<string, RecoveryHandler>;
40
- };
41
- type StepHandler = (ctx: StepContext) => Promise<any>;
42
- type Step = {
43
- name: string;
44
- handler: StepHandler;
45
- options: Required<Pick<StepOptions, "dryRun">> & Omit<StepOptions, "dryRun">;
46
- };
47
- type RunnerConfig = {
48
- llmClient?: LLMClient;
49
- dryRun?: boolean;
50
- debug?: boolean;
51
- sessionName?: string;
52
- logDir?: string;
53
- };
54
- type StepHistoryEntry = {
55
- name: string;
56
- status: "completed" | "failed" | "skipped" | "simulated";
57
- duration: number;
58
- };
59
- type DebugBundle = {
60
- timestamp: string;
61
- step: string;
62
- error: string;
63
- stacktrace: string;
64
- screenshotPath: string;
65
- domPath: string;
66
- logPath: string;
67
- stepHistory: StepHistoryEntry[];
68
- pageUrl: string;
69
- visualizationEnabled?: boolean;
70
- };
71
-
72
- export type { DebugBundle, RecoveryHandler, RunnerConfig, Step, StepContext, StepHandler, StepHistoryEntry, StepOptions };
@@ -1,72 +0,0 @@
1
- import { Page } from 'playwright';
2
- import { LoggerApi } from '../../shared/logger/logger.js';
3
- import { LLMClient } from '../../shared/llm/types.js';
4
- import 'zod';
5
-
6
- type StepContext = {
7
- page: Page;
8
- logger: LoggerApi;
9
- config: {
10
- dryRun: boolean;
11
- debug: boolean;
12
- logDir: string;
13
- };
14
- };
15
- type RecoveryHandler = (ctx: {
16
- page: Page;
17
- logger: LoggerApi;
18
- }) => Promise<void>;
19
- type StepOptions = {
20
- /**
21
- * Behavior in dry-run mode:
22
- * - "execute": always run, even in dry-run (e.g., login steps)
23
- * - "skip": skip entirely in dry-run
24
- * - "simulate": call the simulate function instead
25
- *
26
- * Defaults to "skip".
27
- */
28
- dryRun?: "execute" | "skip" | "simulate";
29
- /**
30
- * Function to call instead of the handler when dryRun is "simulate".
31
- */
32
- simulate?: (ctx: {
33
- logger: LoggerApi;
34
- }) => Promise<any>;
35
- /**
36
- * Custom recovery handlers keyed by name.
37
- * These run after built-in popup recovery on failure.
38
- */
39
- recovery?: Record<string, RecoveryHandler>;
40
- };
41
- type StepHandler = (ctx: StepContext) => Promise<any>;
42
- type Step = {
43
- name: string;
44
- handler: StepHandler;
45
- options: Required<Pick<StepOptions, "dryRun">> & Omit<StepOptions, "dryRun">;
46
- };
47
- type RunnerConfig = {
48
- llmClient?: LLMClient;
49
- dryRun?: boolean;
50
- debug?: boolean;
51
- sessionName?: string;
52
- logDir?: string;
53
- };
54
- type StepHistoryEntry = {
55
- name: string;
56
- status: "completed" | "failed" | "skipped" | "simulated";
57
- duration: number;
58
- };
59
- type DebugBundle = {
60
- timestamp: string;
61
- step: string;
62
- error: string;
63
- stacktrace: string;
64
- screenshotPath: string;
65
- domPath: string;
66
- logPath: string;
67
- stepHistory: StepHistoryEntry[];
68
- pageUrl: string;
69
- visualizationEnabled?: boolean;
70
- };
71
-
72
- export type { DebugBundle, RecoveryHandler, RunnerConfig, Step, StepContext, StepHandler, StepHistoryEntry, StepOptions };
File without changes