libretto 0.2.0 → 0.2.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.
Files changed (69) 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 +15 -11
  50. package/scripts/postinstall.mjs +48 -0
  51. package/skill/SKILL.md +438 -0
  52. package/skill/code-generation-rules.md +190 -0
  53. package/skill/integration-approach-selection.md +174 -0
  54. package/dist/runtime/step/index.cjs +0 -31
  55. package/dist/runtime/step/index.d.cts +0 -7
  56. package/dist/runtime/step/index.d.ts +0 -7
  57. package/dist/runtime/step/index.js +0 -6
  58. package/dist/runtime/step/runner.cjs +0 -208
  59. package/dist/runtime/step/runner.d.cts +0 -16
  60. package/dist/runtime/step/runner.d.ts +0 -16
  61. package/dist/runtime/step/runner.js +0 -187
  62. package/dist/runtime/step/step.cjs +0 -67
  63. package/dist/runtime/step/step.d.cts +0 -23
  64. package/dist/runtime/step/step.d.ts +0 -23
  65. package/dist/runtime/step/step.js +0 -43
  66. package/dist/runtime/step/types.cjs +0 -16
  67. package/dist/runtime/step/types.d.cts +0 -72
  68. package/dist/runtime/step/types.d.ts +0 -72
  69. package/dist/runtime/step/types.js +0 -0
@@ -0,0 +1,491 @@
1
+ async function installSessionTelemetry(options) {
2
+ const STATIC_EXT_RE = /\.(css|js|png|jpg|jpeg|gif|woff|woff2|ttf|ico|svg)(\?|$)/i;
3
+ const { context, initialPage, logAction, logNetwork } = options;
4
+ const includeUserDomActions = options.includeUserDomActions ?? false;
5
+ const pageIdCache = /* @__PURE__ */ new WeakMap();
6
+ const wrappedPages = /* @__PURE__ */ new WeakSet();
7
+ const exposedPages = /* @__PURE__ */ new WeakSet();
8
+ const resolvePageId = async (page) => {
9
+ if (pageIdCache.has(page)) return pageIdCache.get(page);
10
+ const cdpSession = await context.newCDPSession(page);
11
+ try {
12
+ const targetInfo = await cdpSession.send("Target.getTargetInfo");
13
+ const targetId = targetInfo?.targetInfo?.targetId;
14
+ if (typeof targetId !== "string" || targetId.length === 0) {
15
+ throw new Error(`Could not resolve target id for page at URL "${page.url()}".`);
16
+ }
17
+ pageIdCache.set(page, targetId);
18
+ return targetId;
19
+ } finally {
20
+ await cdpSession.detach();
21
+ }
22
+ };
23
+ const emitAction = (entry) => {
24
+ logAction({
25
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
26
+ ...entry
27
+ });
28
+ };
29
+ const emitNetwork = (entry) => {
30
+ logNetwork({
31
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
32
+ ...entry
33
+ });
34
+ };
35
+ const markApiActionInProgress = async (page, inProgress) => {
36
+ await page.evaluate((flag) => {
37
+ window.__btApiActionInProgress = flag;
38
+ }, inProgress);
39
+ };
40
+ const wrapLocator = (locator, page, pageId) => {
41
+ if (locator.__librettoActionLogged) return locator;
42
+ locator.__librettoActionLogged = true;
43
+ const locatorActionMethods = [
44
+ "click",
45
+ "dblclick",
46
+ "fill",
47
+ "type",
48
+ "press",
49
+ "check",
50
+ "uncheck",
51
+ "selectOption",
52
+ "hover",
53
+ "focus",
54
+ "scrollIntoViewIfNeeded",
55
+ "waitFor",
56
+ "innerHTML",
57
+ "innerText",
58
+ "textContent",
59
+ "inputValue",
60
+ "isChecked",
61
+ "isDisabled",
62
+ "isEditable",
63
+ "isEnabled",
64
+ "isHidden",
65
+ "isVisible",
66
+ "count",
67
+ "boundingBox",
68
+ "screenshot",
69
+ "evaluate",
70
+ "evaluateAll",
71
+ "evaluateHandle",
72
+ "getAttribute",
73
+ "dispatchEvent",
74
+ "setInputFiles",
75
+ "selectText",
76
+ "dragTo",
77
+ "highlight",
78
+ "tap"
79
+ ];
80
+ const locatorReturningMethods = [
81
+ "first",
82
+ "last",
83
+ "locator",
84
+ "getByRole",
85
+ "getByText",
86
+ "getByLabel",
87
+ "getByPlaceholder",
88
+ "getByAltText",
89
+ "getByTitle",
90
+ "getByTestId",
91
+ "filter",
92
+ "and",
93
+ "or"
94
+ ];
95
+ for (const actMethod of locatorActionMethods) {
96
+ if (typeof locator[actMethod] !== "function") continue;
97
+ const originalAction = locator[actMethod].bind(locator);
98
+ locator[actMethod] = async (...actionArgs) => {
99
+ const start = Date.now();
100
+ await markApiActionInProgress(page, true);
101
+ try {
102
+ const result = await originalAction(...actionArgs);
103
+ emitAction({
104
+ pageId,
105
+ action: actMethod,
106
+ source: "agent",
107
+ selector: "locator",
108
+ value: actionArgs[0] !== void 0 ? String(actionArgs[0]).slice(0, 100) : void 0,
109
+ duration: Date.now() - start,
110
+ success: true
111
+ });
112
+ return result;
113
+ } catch (error) {
114
+ emitAction({
115
+ pageId,
116
+ action: actMethod,
117
+ source: "agent",
118
+ selector: "locator",
119
+ duration: Date.now() - start,
120
+ success: false,
121
+ error: error?.message ?? String(error)
122
+ });
123
+ throw error;
124
+ } finally {
125
+ await markApiActionInProgress(page, false);
126
+ }
127
+ };
128
+ }
129
+ for (const method of locatorReturningMethods) {
130
+ if (typeof locator[method] !== "function") continue;
131
+ const originalMethod = locator[method].bind(locator);
132
+ locator[method] = (...args) => {
133
+ const child = originalMethod(...args);
134
+ return wrapLocator(child, page, pageId);
135
+ };
136
+ }
137
+ if (typeof locator.nth === "function") {
138
+ const originalNth = locator.nth.bind(locator);
139
+ locator.nth = (index) => {
140
+ const child = originalNth(index);
141
+ return wrapLocator(child, page, pageId);
142
+ };
143
+ }
144
+ if (typeof locator.all === "function") {
145
+ const originalAll = locator.all.bind(locator);
146
+ locator.all = async () => {
147
+ const items = await originalAll();
148
+ return items.map((item) => wrapLocator(item, page, pageId));
149
+ };
150
+ }
151
+ return locator;
152
+ };
153
+ const installUserDomTracking = async (page, pageId) => {
154
+ if (exposedPages.has(page)) return;
155
+ exposedPages.add(page);
156
+ await page.exposeFunction("__btActionLog", (jsonStr) => {
157
+ const parsed = JSON.parse(jsonStr);
158
+ emitAction({
159
+ pageId,
160
+ source: "user",
161
+ ...parsed
162
+ });
163
+ });
164
+ await page.addInitScript(() => {
165
+ if (window.__btDomListenersInstalled) return;
166
+ window.__btDomListenersInstalled = true;
167
+ const identify = (el) => {
168
+ if (!el || !el.tagName) return "";
169
+ const testId = el.getAttribute("data-testid");
170
+ if (testId) return `[data-testid="${testId}"]`;
171
+ const role = el.getAttribute("role") || "";
172
+ const id = el.id;
173
+ if (role && id) return `${role}#${id}`;
174
+ const label = el.getAttribute("aria-label") || (el.textContent || "").trim().slice(0, 30) || "";
175
+ if (role && label) return `${role} "${label}"`;
176
+ const tag = el.tagName.toLowerCase();
177
+ const cls = el.className && typeof el.className === "string" ? "." + el.className.trim().split(/\s+/).slice(0, 2).join(".") : "";
178
+ return `${tag}${cls}`;
179
+ };
180
+ let clickTimer = null;
181
+ let pendingClick = null;
182
+ document.addEventListener(
183
+ "click",
184
+ (event) => {
185
+ if (window.__btApiActionInProgress) return;
186
+ const target = event.target;
187
+ const selector = identify(target);
188
+ if (target?.type === "checkbox") {
189
+ window.__btActionLog(
190
+ JSON.stringify({
191
+ action: target.checked ? "check" : "uncheck",
192
+ selector,
193
+ success: true
194
+ })
195
+ );
196
+ return;
197
+ }
198
+ pendingClick = { selector };
199
+ if (clickTimer) clearTimeout(clickTimer);
200
+ clickTimer = setTimeout(() => {
201
+ if (pendingClick) {
202
+ window.__btActionLog(
203
+ JSON.stringify({
204
+ action: "click",
205
+ selector: pendingClick.selector,
206
+ success: true
207
+ })
208
+ );
209
+ }
210
+ pendingClick = null;
211
+ clickTimer = null;
212
+ }, 200);
213
+ },
214
+ true
215
+ );
216
+ document.addEventListener(
217
+ "dblclick",
218
+ (event) => {
219
+ if (window.__btApiActionInProgress) return;
220
+ if (clickTimer) {
221
+ clearTimeout(clickTimer);
222
+ clickTimer = null;
223
+ pendingClick = null;
224
+ }
225
+ const selector = identify(event.target);
226
+ window.__btActionLog(
227
+ JSON.stringify({ action: "dblclick", selector, success: true })
228
+ );
229
+ },
230
+ true
231
+ );
232
+ const inputTimers = /* @__PURE__ */ new WeakMap();
233
+ document.addEventListener(
234
+ "input",
235
+ (event) => {
236
+ if (window.__btApiActionInProgress) return;
237
+ const target = event.target;
238
+ const selector = identify(target);
239
+ if (target.tagName === "SELECT") {
240
+ window.__btActionLog(
241
+ JSON.stringify({
242
+ action: "selectOption",
243
+ selector,
244
+ value: target.value,
245
+ success: true
246
+ })
247
+ );
248
+ return;
249
+ }
250
+ const existing = inputTimers.get(target);
251
+ if (existing) clearTimeout(existing);
252
+ inputTimers.set(
253
+ target,
254
+ setTimeout(() => {
255
+ inputTimers.delete(target);
256
+ window.__btActionLog(
257
+ JSON.stringify({
258
+ action: "fill",
259
+ selector,
260
+ value: (target.value || "").slice(0, 100),
261
+ success: true
262
+ })
263
+ );
264
+ }, 500)
265
+ );
266
+ },
267
+ true
268
+ );
269
+ const specialKeys = /* @__PURE__ */ new Set([
270
+ "Enter",
271
+ "Escape",
272
+ "Tab",
273
+ "Backspace",
274
+ "Delete",
275
+ "ArrowUp",
276
+ "ArrowDown",
277
+ "ArrowLeft",
278
+ "ArrowRight",
279
+ "Home",
280
+ "End",
281
+ "PageUp",
282
+ "PageDown",
283
+ "F1",
284
+ "F2",
285
+ "F3",
286
+ "F4",
287
+ "F5",
288
+ "F6",
289
+ "F7",
290
+ "F8",
291
+ "F9",
292
+ "F10",
293
+ "F11",
294
+ "F12"
295
+ ]);
296
+ document.addEventListener(
297
+ "keydown",
298
+ (event) => {
299
+ if (window.__btApiActionInProgress) return;
300
+ const isShortcut = event.ctrlKey || event.metaKey || event.altKey;
301
+ if (!isShortcut && !specialKeys.has(event.key)) return;
302
+ const selector = identify(event.target);
303
+ const keyDesc = (event.ctrlKey ? "Ctrl+" : "") + (event.metaKey ? "Meta+" : "") + (event.altKey ? "Alt+" : "") + (event.shiftKey ? "Shift+" : "") + event.key;
304
+ window.__btActionLog(
305
+ JSON.stringify({
306
+ action: "press",
307
+ selector,
308
+ value: keyDesc,
309
+ success: true
310
+ })
311
+ );
312
+ },
313
+ true
314
+ );
315
+ let scrollTimer = null;
316
+ document.addEventListener(
317
+ "scroll",
318
+ () => {
319
+ if (window.__btApiActionInProgress) return;
320
+ if (scrollTimer) clearTimeout(scrollTimer);
321
+ scrollTimer = setTimeout(() => {
322
+ scrollTimer = null;
323
+ window.__btActionLog(
324
+ JSON.stringify({
325
+ action: "scroll",
326
+ selector: "document",
327
+ value: `y=${window.scrollY}`,
328
+ success: true
329
+ })
330
+ );
331
+ }, 300);
332
+ },
333
+ true
334
+ );
335
+ });
336
+ };
337
+ const wrapPageActions = (page, pageId) => {
338
+ if (wrappedPages.has(page)) return;
339
+ wrappedPages.add(page);
340
+ const pageActions = [
341
+ "click",
342
+ "dblclick",
343
+ "fill",
344
+ "type",
345
+ "press",
346
+ "check",
347
+ "uncheck",
348
+ "selectOption",
349
+ "hover",
350
+ "focus"
351
+ ];
352
+ const navActions = ["goto", "reload", "goBack", "goForward"];
353
+ const locatorFactories = [
354
+ "locator",
355
+ "getByRole",
356
+ "getByText",
357
+ "getByLabel",
358
+ "getByPlaceholder",
359
+ "getByAltText",
360
+ "getByTitle",
361
+ "getByTestId"
362
+ ];
363
+ for (const method of pageActions) {
364
+ const originalMethod = page[method].bind(page);
365
+ page[method] = async (...args) => {
366
+ const start = Date.now();
367
+ await markApiActionInProgress(page, true);
368
+ try {
369
+ const result = await originalMethod(...args);
370
+ emitAction({
371
+ pageId,
372
+ action: method,
373
+ source: "agent",
374
+ selector: typeof args[0] === "string" ? args[0] : void 0,
375
+ value: args[1] !== void 0 ? String(args[1]).slice(0, 100) : void 0,
376
+ duration: Date.now() - start,
377
+ success: true
378
+ });
379
+ return result;
380
+ } catch (error) {
381
+ emitAction({
382
+ pageId,
383
+ action: method,
384
+ source: "agent",
385
+ selector: typeof args[0] === "string" ? args[0] : void 0,
386
+ duration: Date.now() - start,
387
+ success: false,
388
+ error: error?.message ?? String(error)
389
+ });
390
+ throw error;
391
+ } finally {
392
+ await markApiActionInProgress(page, false);
393
+ }
394
+ };
395
+ }
396
+ for (const method of navActions) {
397
+ const originalMethod = page[method].bind(page);
398
+ page[method] = async (...args) => {
399
+ const start = Date.now();
400
+ try {
401
+ const result = await originalMethod(...args);
402
+ emitAction({
403
+ pageId,
404
+ action: method,
405
+ source: "agent",
406
+ url: typeof args[0] === "string" ? args[0] : page.url(),
407
+ duration: Date.now() - start,
408
+ success: true
409
+ });
410
+ return result;
411
+ } catch (error) {
412
+ emitAction({
413
+ pageId,
414
+ action: method,
415
+ source: "agent",
416
+ url: typeof args[0] === "string" ? args[0] : void 0,
417
+ duration: Date.now() - start,
418
+ success: false,
419
+ error: error?.message ?? String(error)
420
+ });
421
+ throw error;
422
+ }
423
+ };
424
+ }
425
+ for (const factory of locatorFactories) {
426
+ const originalFactory = page[factory].bind(page);
427
+ page[factory] = (...factoryArgs) => {
428
+ const locator = originalFactory(...factoryArgs);
429
+ return wrapLocator(locator, page, pageId);
430
+ };
431
+ }
432
+ };
433
+ const installForPage = async (page) => {
434
+ const pageId = await resolvePageId(page);
435
+ wrapPageActions(page, pageId);
436
+ if (includeUserDomActions) {
437
+ await installUserDomTracking(page, pageId);
438
+ }
439
+ page.on("response", async (response) => {
440
+ const request = response.request();
441
+ const url = request.url();
442
+ if (STATIC_EXT_RE.test(url) || url.startsWith("chrome-extension://")) return;
443
+ emitNetwork({
444
+ pageId,
445
+ method: request.method(),
446
+ url,
447
+ status: response.status(),
448
+ contentType: response.headers()["content-type"] ?? null,
449
+ postData: request.method() === "POST" || request.method() === "PUT" || request.method() === "PATCH" ? (request.postData() ?? "").substring(0, 2e3) : void 0,
450
+ responseBody: null,
451
+ size: null,
452
+ durationMs: null
453
+ });
454
+ });
455
+ page.on("framenavigated", (frame) => {
456
+ if (frame !== page.mainFrame()) return;
457
+ emitAction({
458
+ pageId,
459
+ action: "navigate",
460
+ source: "agent",
461
+ url: frame.url(),
462
+ success: true
463
+ });
464
+ });
465
+ page.on("popup", (popup) => {
466
+ emitAction({
467
+ pageId,
468
+ action: "popup",
469
+ source: "agent",
470
+ url: popup.url(),
471
+ success: true
472
+ });
473
+ });
474
+ page.on("dialog", (dialog) => {
475
+ emitAction({
476
+ pageId,
477
+ action: "dialog",
478
+ source: "agent",
479
+ value: `${dialog.type()}: ${dialog.message().slice(0, 500)}`,
480
+ success: true
481
+ });
482
+ });
483
+ };
484
+ await installForPage(initialPage);
485
+ context.on("page", (newPage) => {
486
+ void installForPage(newPage);
487
+ });
488
+ }
489
+ export {
490
+ installSessionTelemetry
491
+ };
@@ -20,6 +20,9 @@ function readNetworkLog(session, opts = {}) {
20
20
  const re = new RegExp(opts.filter, "i");
21
21
  entries = entries.filter((e) => re.test(e.url));
22
22
  }
23
+ if (opts.pageId) {
24
+ entries = entries.filter((e) => e.pageId === opts.pageId);
25
+ }
23
26
  const last = opts.last ?? 20;
24
27
  if (entries.length > last) {
25
28
  entries = entries.slice(-last);
@@ -79,6 +82,9 @@ function readActionLog(session, opts = {}) {
79
82
  (e) => re.test(e.action) || re.test(e.selector || "") || re.test(e.value || "") || re.test(e.url || "")
80
83
  );
81
84
  }
85
+ if (opts.pageId) {
86
+ entries = entries.filter((e) => e.pageId === opts.pageId);
87
+ }
82
88
  const last = opts.last ?? 20;
83
89
  if (entries.length > last) {
84
90
  entries = entries.slice(-last);
@@ -157,7 +163,7 @@ function formatHint(method, args) {
157
163
  const formatted = args.map((a) => JSON.stringify(a)).join(", ");
158
164
  return `${method}(${formatted})`;
159
165
  }
160
- function wrapLocator(locator, hint, session, page, onActivity) {
166
+ function wrapLocator(locator, hint, session, page, pageId, onActivity) {
161
167
  if (locator.__librettoActionLogged) return locator;
162
168
  locator.__librettoActionLogged = true;
163
169
  for (const actMethod of LOCATOR_ACTION_METHODS) {
@@ -174,6 +180,7 @@ function wrapLocator(locator, hint, session, page, onActivity) {
174
180
  try {
175
181
  const result = await origAct(...actArgs);
176
182
  parentLogAction(session, {
183
+ pageId,
177
184
  action: actMethod,
178
185
  source: "agent",
179
186
  selector: hint,
@@ -185,6 +192,7 @@ function wrapLocator(locator, hint, session, page, onActivity) {
185
192
  return result;
186
193
  } catch (err) {
187
194
  parentLogAction(session, {
195
+ pageId,
188
196
  action: actMethod,
189
197
  source: "agent",
190
198
  selector: hint,
@@ -210,7 +218,7 @@ function wrapLocator(locator, hint, session, page, onActivity) {
210
218
  locator[method] = (...args) => {
211
219
  const child = origMethod(...args);
212
220
  const childHint = args.length > 0 ? `${hint}.${formatHint(method, args)}` : `${hint}.${method}()`;
213
- return wrapLocator(child, childHint, session, page, onActivity);
221
+ return wrapLocator(child, childHint, session, page, pageId, onActivity);
214
222
  };
215
223
  }
216
224
  if (typeof locator.nth === "function") {
@@ -218,7 +226,7 @@ function wrapLocator(locator, hint, session, page, onActivity) {
218
226
  locator.nth = (index) => {
219
227
  const child = origNth(index);
220
228
  const childHint = `${hint}.nth(${index})`;
221
- return wrapLocator(child, childHint, session, page, onActivity);
229
+ return wrapLocator(child, childHint, session, page, pageId, onActivity);
222
230
  };
223
231
  }
224
232
  if (typeof locator.all === "function") {
@@ -227,13 +235,13 @@ function wrapLocator(locator, hint, session, page, onActivity) {
227
235
  const items = await origAll();
228
236
  return items.map((item, i) => {
229
237
  const childHint = `${hint}.all()[${i}]`;
230
- return wrapLocator(item, childHint, session, page, onActivity);
238
+ return wrapLocator(item, childHint, session, page, pageId, onActivity);
231
239
  });
232
240
  };
233
241
  }
234
242
  return locator;
235
243
  }
236
- function wrapPageForActionLogging(page, session, onActivity) {
244
+ function wrapPageForActionLogging(page, session, pageId, onActivity) {
237
245
  const PAGE_ACTIONS = [
238
246
  "click",
239
247
  "dblclick",
@@ -260,6 +268,7 @@ function wrapPageForActionLogging(page, session, onActivity) {
260
268
  try {
261
269
  const result = await orig(...args);
262
270
  parentLogAction(session, {
271
+ pageId,
263
272
  action: method,
264
273
  source: "agent",
265
274
  selector: typeof args[0] === "string" ? args[0] : void 0,
@@ -271,6 +280,7 @@ function wrapPageForActionLogging(page, session, onActivity) {
271
280
  return result;
272
281
  } catch (err) {
273
282
  parentLogAction(session, {
283
+ pageId,
274
284
  action: method,
275
285
  source: "agent",
276
286
  selector: typeof args[0] === "string" ? args[0] : void 0,
@@ -297,6 +307,7 @@ function wrapPageForActionLogging(page, session, onActivity) {
297
307
  try {
298
308
  const result = await orig(...args);
299
309
  parentLogAction(session, {
310
+ pageId,
300
311
  action: method,
301
312
  source: "agent",
302
313
  url: typeof args[0] === "string" ? args[0] : page.url(),
@@ -307,6 +318,7 @@ function wrapPageForActionLogging(page, session, onActivity) {
307
318
  return result;
308
319
  } catch (err) {
309
320
  parentLogAction(session, {
321
+ pageId,
310
322
  action: method,
311
323
  source: "agent",
312
324
  url: typeof args[0] === "string" ? args[0] : void 0,
@@ -334,7 +346,7 @@ function wrapPageForActionLogging(page, session, onActivity) {
334
346
  page[factory] = (...factoryArgs) => {
335
347
  const locator = orig(...factoryArgs);
336
348
  const hint = formatHint(factory, factoryArgs);
337
- return wrapLocator(locator, hint, session, page, onActivity);
349
+ return wrapLocator(locator, hint, session, page, pageId, onActivity);
338
350
  };
339
351
  }
340
352
  }
@@ -7,8 +7,13 @@ import {
7
7
  launchBrowser
8
8
  } from "../../index.js";
9
9
  import { getProfilePath, normalizeDomain } from "../core/browser.js";
10
- import { getSessionDir } from "../core/context.js";
10
+ import {
11
+ getSessionActionsLogPath,
12
+ getSessionDir,
13
+ getSessionNetworkLogPath
14
+ } from "../core/context.js";
11
15
  import { getPauseSignalPaths, removeSignalIfExists } from "../core/pause-signals.js";
16
+ import { installSessionTelemetry } from "../core/session-telemetry.js";
12
17
  const LIBRETTO_WORKFLOW_BRAND = /* @__PURE__ */ Symbol.for("libretto.workflow");
13
18
  const RESUME_POLL_INTERVAL_MS = 250;
14
19
  function mirrorStdoutToFile(filePath) {
@@ -136,6 +141,19 @@ async function runIntegrationInternal(args, options) {
136
141
  headless: args.headless,
137
142
  storageStatePath
138
143
  });
144
+ const actionsLogPath = getSessionActionsLogPath(args.session);
145
+ const networkLogPath = getSessionNetworkLogPath(args.session);
146
+ await installSessionTelemetry({
147
+ context: browserSession.context,
148
+ initialPage: browserSession.page,
149
+ includeUserDomActions: true,
150
+ logAction: (entry) => {
151
+ appendFileSync(actionsLogPath, JSON.stringify(entry) + "\n");
152
+ },
153
+ logNetwork: (entry) => {
154
+ appendFileSync(networkLogPath, JSON.stringify(entry) + "\n");
155
+ }
156
+ });
139
157
  const workflowContext = {
140
158
  logger: integrationLogger,
141
159
  page: browserSession.page,
package/dist/index.cjs CHANGED
@@ -29,8 +29,8 @@ __export(index_exports, {
29
29
  attemptWithRecovery: () => import_recovery.attemptWithRecovery,
30
30
  clearHighlights: () => import_highlight.clearHighlights,
31
31
  createFileLogSink: () => import_sinks.createFileLogSink,
32
- createRunner: () => import_runner.createRunner,
33
32
  debugPause: () => import_pause.debugPause,
33
+ defaultLogger: () => import_logger.defaultLogger,
34
34
  detectSubmissionError: () => import_errors.detectSubmissionError,
35
35
  downloadAndSave: () => import_download.downloadAndSave,
36
36
  downloadViaClick: () => import_download.downloadViaClick,
@@ -58,12 +58,9 @@ __export(index_exports, {
58
58
  serializeSessionState: () => import_state.serializeSessionState,
59
59
  shouldPauseBeforeMutation: () => import_config.shouldPauseBeforeMutation,
60
60
  showHighlight: () => import_highlight.showHighlight,
61
- step: () => import_step.step,
62
61
  workflow: () => import_workflow.workflow
63
62
  });
64
63
  module.exports = __toCommonJS(index_exports);
65
- var import_step = require("./runtime/step/step.js");
66
- var import_runner = require("./runtime/step/runner.js");
67
64
  var import_logger = require("./shared/logger/logger.js");
68
65
  var import_sinks = require("./shared/logger/sinks.js");
69
66
  var import_state = require("./shared/state/index.js");
@@ -93,8 +90,8 @@ var import_workflow = require("./shared/workflow/workflow.js");
93
90
  attemptWithRecovery,
94
91
  clearHighlights,
95
92
  createFileLogSink,
96
- createRunner,
97
93
  debugPause,
94
+ defaultLogger,
98
95
  detectSubmissionError,
99
96
  downloadAndSave,
100
97
  downloadViaClick,
@@ -122,6 +119,5 @@ var import_workflow = require("./shared/workflow/workflow.js");
122
119
  serializeSessionState,
123
120
  shouldPauseBeforeMutation,
124
121
  showHighlight,
125
- step,
126
122
  workflow
127
123
  });
package/dist/index.d.cts CHANGED
@@ -1,7 +1,4 @@
1
- export { step } from './runtime/step/step.cjs';
2
- export { Runner, createRunner } from './runtime/step/runner.cjs';
3
- export { DebugBundle, RecoveryHandler, RunnerConfig, Step, StepContext, StepHandler, StepHistoryEntry, StepOptions } from './runtime/step/types.cjs';
4
- export { LogOptions, Logger, LoggerApi, LoggerSink } from './shared/logger/logger.cjs';
1
+ export { LogOptions, Logger, LoggerApi, LoggerSink, MinimalLogger, defaultLogger } from './shared/logger/logger.cjs';
5
2
  export { createFileLogSink, jsonlConsoleSink, prettyConsoleSink } from './shared/logger/sinks.cjs';
6
3
  export { LLMClient, Message, MessageContentPart } from './shared/llm/types.cjs';
7
4
  export { SESSION_STATE_VERSION, SessionState, SessionStateFile, SessionStateFileSchema, SessionStatus, SessionStatusSchema, parseSessionStateContent, parseSessionStateData, serializeSessionState } from './shared/state/session-state.cjs';
@@ -18,5 +15,5 @@ export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, mov
18
15
  export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.cjs';
19
16
  export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.cjs';
20
17
  export { LIBRETTO_WORKFLOW_BRAND, LibrettoAuthProfile, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowMetadata, workflow } from './shared/workflow/workflow.cjs';
21
- import 'playwright';
22
18
  import 'zod';
19
+ import 'playwright';