libretto 0.2.6 → 0.3.0

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 (160) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +12 -12
  3. package/skill/SKILL.md +20 -18
  4. package/skill/code-generation-rules.md +3 -3
  5. package/skill/integration-approach-selection.md +3 -3
  6. package/dist/cli/cli.js +0 -209
  7. package/dist/cli/commands/ai.js +0 -21
  8. package/dist/cli/commands/browser.js +0 -82
  9. package/dist/cli/commands/execution.js +0 -461
  10. package/dist/cli/commands/init.js +0 -95
  11. package/dist/cli/commands/logs.js +0 -93
  12. package/dist/cli/commands/snapshot.js +0 -106
  13. package/dist/cli/core/ai-config.js +0 -149
  14. package/dist/cli/core/browser.js +0 -648
  15. package/dist/cli/core/context.js +0 -118
  16. package/dist/cli/core/pause-signals.js +0 -29
  17. package/dist/cli/core/session-telemetry.js +0 -491
  18. package/dist/cli/core/session.js +0 -183
  19. package/dist/cli/core/snapshot-analyzer.js +0 -492
  20. package/dist/cli/core/telemetry.js +0 -362
  21. package/dist/cli/index.js +0 -13
  22. package/dist/cli/workers/run-integration-runtime.js +0 -227
  23. package/dist/cli/workers/run-integration-worker-protocol.js +0 -12
  24. package/dist/cli/workers/run-integration-worker.js +0 -66
  25. package/dist/index.cjs +0 -116
  26. package/dist/index.d.cts +0 -21
  27. package/dist/index.d.ts +0 -21
  28. package/dist/index.js +0 -97
  29. package/dist/runtime/download/download.cjs +0 -70
  30. package/dist/runtime/download/download.d.cts +0 -35
  31. package/dist/runtime/download/download.d.ts +0 -35
  32. package/dist/runtime/download/download.js +0 -45
  33. package/dist/runtime/download/index.cjs +0 -30
  34. package/dist/runtime/download/index.d.cts +0 -3
  35. package/dist/runtime/download/index.d.ts +0 -3
  36. package/dist/runtime/download/index.js +0 -8
  37. package/dist/runtime/extract/extract.cjs +0 -88
  38. package/dist/runtime/extract/extract.d.cts +0 -23
  39. package/dist/runtime/extract/extract.d.ts +0 -23
  40. package/dist/runtime/extract/extract.js +0 -64
  41. package/dist/runtime/extract/index.cjs +0 -28
  42. package/dist/runtime/extract/index.d.cts +0 -5
  43. package/dist/runtime/extract/index.d.ts +0 -5
  44. package/dist/runtime/extract/index.js +0 -4
  45. package/dist/runtime/network/index.cjs +0 -28
  46. package/dist/runtime/network/index.d.cts +0 -4
  47. package/dist/runtime/network/index.d.ts +0 -4
  48. package/dist/runtime/network/index.js +0 -6
  49. package/dist/runtime/network/network.cjs +0 -91
  50. package/dist/runtime/network/network.d.cts +0 -28
  51. package/dist/runtime/network/network.d.ts +0 -28
  52. package/dist/runtime/network/network.js +0 -67
  53. package/dist/runtime/recovery/agent.cjs +0 -223
  54. package/dist/runtime/recovery/agent.d.cts +0 -13
  55. package/dist/runtime/recovery/agent.d.ts +0 -13
  56. package/dist/runtime/recovery/agent.js +0 -199
  57. package/dist/runtime/recovery/errors.cjs +0 -124
  58. package/dist/runtime/recovery/errors.d.cts +0 -31
  59. package/dist/runtime/recovery/errors.d.ts +0 -31
  60. package/dist/runtime/recovery/errors.js +0 -100
  61. package/dist/runtime/recovery/index.cjs +0 -34
  62. package/dist/runtime/recovery/index.d.cts +0 -7
  63. package/dist/runtime/recovery/index.d.ts +0 -7
  64. package/dist/runtime/recovery/index.js +0 -10
  65. package/dist/runtime/recovery/recovery.cjs +0 -55
  66. package/dist/runtime/recovery/recovery.d.cts +0 -12
  67. package/dist/runtime/recovery/recovery.d.ts +0 -12
  68. package/dist/runtime/recovery/recovery.js +0 -31
  69. package/dist/shared/config/config.cjs +0 -44
  70. package/dist/shared/config/config.d.cts +0 -10
  71. package/dist/shared/config/config.d.ts +0 -10
  72. package/dist/shared/config/config.js +0 -18
  73. package/dist/shared/config/index.cjs +0 -32
  74. package/dist/shared/config/index.d.cts +0 -1
  75. package/dist/shared/config/index.d.ts +0 -1
  76. package/dist/shared/config/index.js +0 -10
  77. package/dist/shared/debug/index.cjs +0 -30
  78. package/dist/shared/debug/index.d.cts +0 -1
  79. package/dist/shared/debug/index.d.ts +0 -1
  80. package/dist/shared/debug/index.js +0 -5
  81. package/dist/shared/debug/pause.cjs +0 -90
  82. package/dist/shared/debug/pause.d.cts +0 -16
  83. package/dist/shared/debug/pause.d.ts +0 -16
  84. package/dist/shared/debug/pause.js +0 -55
  85. package/dist/shared/instrumentation/errors.cjs +0 -81
  86. package/dist/shared/instrumentation/errors.d.cts +0 -12
  87. package/dist/shared/instrumentation/errors.d.ts +0 -12
  88. package/dist/shared/instrumentation/errors.js +0 -57
  89. package/dist/shared/instrumentation/index.cjs +0 -35
  90. package/dist/shared/instrumentation/index.d.cts +0 -6
  91. package/dist/shared/instrumentation/index.d.ts +0 -6
  92. package/dist/shared/instrumentation/index.js +0 -12
  93. package/dist/shared/instrumentation/instrument.cjs +0 -206
  94. package/dist/shared/instrumentation/instrument.d.cts +0 -32
  95. package/dist/shared/instrumentation/instrument.d.ts +0 -32
  96. package/dist/shared/instrumentation/instrument.js +0 -190
  97. package/dist/shared/llm/ai-sdk-adapter.cjs +0 -67
  98. package/dist/shared/llm/ai-sdk-adapter.d.cts +0 -22
  99. package/dist/shared/llm/ai-sdk-adapter.d.ts +0 -22
  100. package/dist/shared/llm/ai-sdk-adapter.js +0 -43
  101. package/dist/shared/llm/client.cjs +0 -139
  102. package/dist/shared/llm/client.d.cts +0 -6
  103. package/dist/shared/llm/client.d.ts +0 -6
  104. package/dist/shared/llm/client.js +0 -115
  105. package/dist/shared/llm/index.cjs +0 -31
  106. package/dist/shared/llm/index.d.cts +0 -5
  107. package/dist/shared/llm/index.d.ts +0 -5
  108. package/dist/shared/llm/index.js +0 -6
  109. package/dist/shared/llm/types.cjs +0 -16
  110. package/dist/shared/llm/types.d.cts +0 -66
  111. package/dist/shared/llm/types.d.ts +0 -66
  112. package/dist/shared/llm/types.js +0 -0
  113. package/dist/shared/logger/index.cjs +0 -37
  114. package/dist/shared/logger/index.d.cts +0 -2
  115. package/dist/shared/logger/index.d.ts +0 -2
  116. package/dist/shared/logger/index.js +0 -13
  117. package/dist/shared/logger/logger.cjs +0 -213
  118. package/dist/shared/logger/logger.d.cts +0 -82
  119. package/dist/shared/logger/logger.d.ts +0 -82
  120. package/dist/shared/logger/logger.js +0 -188
  121. package/dist/shared/logger/sinks.cjs +0 -160
  122. package/dist/shared/logger/sinks.d.cts +0 -9
  123. package/dist/shared/logger/sinks.d.ts +0 -9
  124. package/dist/shared/logger/sinks.js +0 -124
  125. package/dist/shared/paths/paths.cjs +0 -104
  126. package/dist/shared/paths/paths.d.cts +0 -10
  127. package/dist/shared/paths/paths.d.ts +0 -10
  128. package/dist/shared/paths/paths.js +0 -73
  129. package/dist/shared/run/api.cjs +0 -28
  130. package/dist/shared/run/api.d.cts +0 -2
  131. package/dist/shared/run/api.d.ts +0 -2
  132. package/dist/shared/run/api.js +0 -4
  133. package/dist/shared/run/browser.cjs +0 -98
  134. package/dist/shared/run/browser.d.cts +0 -22
  135. package/dist/shared/run/browser.d.ts +0 -22
  136. package/dist/shared/run/browser.js +0 -74
  137. package/dist/shared/state/index.cjs +0 -38
  138. package/dist/shared/state/index.d.cts +0 -2
  139. package/dist/shared/state/index.d.ts +0 -2
  140. package/dist/shared/state/index.js +0 -16
  141. package/dist/shared/state/session-state.cjs +0 -85
  142. package/dist/shared/state/session-state.d.cts +0 -34
  143. package/dist/shared/state/session-state.d.ts +0 -34
  144. package/dist/shared/state/session-state.js +0 -56
  145. package/dist/shared/visualization/ghost-cursor.cjs +0 -174
  146. package/dist/shared/visualization/ghost-cursor.d.cts +0 -37
  147. package/dist/shared/visualization/ghost-cursor.d.ts +0 -37
  148. package/dist/shared/visualization/ghost-cursor.js +0 -145
  149. package/dist/shared/visualization/highlight.cjs +0 -134
  150. package/dist/shared/visualization/highlight.d.cts +0 -22
  151. package/dist/shared/visualization/highlight.d.ts +0 -22
  152. package/dist/shared/visualization/highlight.js +0 -108
  153. package/dist/shared/visualization/index.cjs +0 -45
  154. package/dist/shared/visualization/index.d.cts +0 -3
  155. package/dist/shared/visualization/index.d.ts +0 -3
  156. package/dist/shared/visualization/index.js +0 -24
  157. package/dist/shared/workflow/workflow.cjs +0 -47
  158. package/dist/shared/workflow/workflow.d.cts +0 -21
  159. package/dist/shared/workflow/workflow.d.ts +0 -21
  160. package/dist/shared/workflow/workflow.js +0 -21
@@ -1,362 +0,0 @@
1
- import { appendFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
2
- import {
3
- getSessionActionsLogPath,
4
- getSessionNetworkLogPath
5
- } from "./context.js";
6
- import { assertSessionStateExistsOrThrow } from "./session.js";
7
- function readNetworkLog(session, opts = {}) {
8
- assertSessionStateExistsOrThrow(session);
9
- const logPath = getSessionNetworkLogPath(session);
10
- if (!existsSync(logPath)) return [];
11
- const lines = readFileSync(logPath, "utf-8").trim().split("\n").filter(Boolean);
12
- let entries = lines.map(
13
- (line) => JSON.parse(line)
14
- );
15
- if (opts.method) {
16
- const m = opts.method.toUpperCase();
17
- entries = entries.filter((e) => e.method === m);
18
- }
19
- if (opts.filter) {
20
- const re = new RegExp(opts.filter, "i");
21
- entries = entries.filter((e) => re.test(e.url));
22
- }
23
- if (opts.pageId) {
24
- entries = entries.filter((e) => e.pageId === opts.pageId);
25
- }
26
- const last = opts.last ?? 20;
27
- if (entries.length > last) {
28
- entries = entries.slice(-last);
29
- }
30
- return entries;
31
- }
32
- function formatNetworkEntry(e) {
33
- const time = e.ts.replace(/.*T/, "").replace(/\.\d+Z$/, "");
34
- const duration = e.durationMs != null ? `${e.durationMs}ms` : "?ms";
35
- const size = e.size != null ? `${e.size}B` : "";
36
- const parts = [
37
- `[${time}]`,
38
- `${e.status}`,
39
- `${e.method.padEnd(6)}`,
40
- e.url,
41
- duration,
42
- size
43
- ].filter(Boolean);
44
- let line = parts.join(" ");
45
- if (e.postData) {
46
- line += `
47
- body: ${e.postData.substring(0, 120)}${e.postData.length > 120 ? "..." : ""}`;
48
- }
49
- return line;
50
- }
51
- function clearNetworkLog(session) {
52
- assertSessionStateExistsOrThrow(session);
53
- const logPath = getSessionNetworkLogPath(session);
54
- writeFileSync(logPath, "");
55
- }
56
- function parentLogAction(session, entry) {
57
- try {
58
- const record = { ts: (/* @__PURE__ */ new Date()).toISOString(), ...entry };
59
- appendFileSync(getSessionActionsLogPath(session), JSON.stringify(record) + "\n");
60
- } catch {
61
- }
62
- }
63
- function readActionLog(session, opts = {}) {
64
- assertSessionStateExistsOrThrow(session);
65
- const logPath = getSessionActionsLogPath(session);
66
- if (!existsSync(logPath)) return [];
67
- const lines = readFileSync(logPath, "utf-8").trim().split("\n").filter(Boolean);
68
- let entries = lines.map(
69
- (line) => JSON.parse(line)
70
- );
71
- if (opts.action) {
72
- const a = opts.action.toLowerCase();
73
- entries = entries.filter((e) => e.action === a);
74
- }
75
- if (opts.source) {
76
- const s = opts.source.toLowerCase();
77
- entries = entries.filter((e) => e.source === s);
78
- }
79
- if (opts.filter) {
80
- const re = new RegExp(opts.filter, "i");
81
- entries = entries.filter(
82
- (e) => re.test(e.action) || re.test(e.selector || "") || re.test(e.value || "") || re.test(e.url || "")
83
- );
84
- }
85
- if (opts.pageId) {
86
- entries = entries.filter((e) => e.pageId === opts.pageId);
87
- }
88
- const last = opts.last ?? 20;
89
- if (entries.length > last) {
90
- entries = entries.slice(-last);
91
- }
92
- return entries;
93
- }
94
- function formatActionEntry(e) {
95
- const time = e.ts.replace(/.*T/, "").replace(/\.\d+Z$/, "");
96
- const src = e.source.toUpperCase().padEnd(5);
97
- const parts = [`[${time}]`, `[${src}]`, e.action];
98
- if (e.selector) parts.push(e.selector);
99
- if (e.value) parts.push(`"${e.value}"`);
100
- if (e.url) parts.push(e.url);
101
- if (e.duration != null) parts.push(`${e.duration}ms`);
102
- if (!e.success) parts.push(`ERROR: ${e.error || "unknown"}`);
103
- return parts.join(" ");
104
- }
105
- function clearActionLog(session) {
106
- assertSessionStateExistsOrThrow(session);
107
- const logPath = getSessionActionsLogPath(session);
108
- writeFileSync(logPath, "");
109
- }
110
- const LOCATOR_ACTION_METHODS = [
111
- "click",
112
- "dblclick",
113
- "fill",
114
- "type",
115
- "press",
116
- "check",
117
- "uncheck",
118
- "selectOption",
119
- "hover",
120
- "focus",
121
- "scrollIntoViewIfNeeded",
122
- "waitFor",
123
- "innerHTML",
124
- "innerText",
125
- "textContent",
126
- "inputValue",
127
- "isChecked",
128
- "isDisabled",
129
- "isEditable",
130
- "isEnabled",
131
- "isHidden",
132
- "isVisible",
133
- "count",
134
- "boundingBox",
135
- "screenshot",
136
- "evaluate",
137
- "evaluateAll",
138
- "evaluateHandle",
139
- "getAttribute",
140
- "dispatchEvent",
141
- "setInputFiles",
142
- "selectText",
143
- "dragTo",
144
- "highlight",
145
- "tap"
146
- ];
147
- const LOCATOR_RETURNING_METHODS = [
148
- "first",
149
- "last",
150
- "locator",
151
- "getByRole",
152
- "getByText",
153
- "getByLabel",
154
- "getByPlaceholder",
155
- "getByAltText",
156
- "getByTitle",
157
- "getByTestId",
158
- "filter",
159
- "and",
160
- "or"
161
- ];
162
- function formatHint(method, args) {
163
- const formatted = args.map((a) => JSON.stringify(a)).join(", ");
164
- return `${method}(${formatted})`;
165
- }
166
- function wrapLocator(locator, hint, session, page, pageId, onActivity) {
167
- if (locator.__librettoActionLogged) return locator;
168
- locator.__librettoActionLogged = true;
169
- for (const actMethod of LOCATOR_ACTION_METHODS) {
170
- if (typeof locator[actMethod] !== "function") continue;
171
- const origAct = locator[actMethod].bind(locator);
172
- locator[actMethod] = async (...actArgs) => {
173
- const start = Date.now();
174
- try {
175
- await page.evaluate(() => {
176
- window.__btApiActionInProgress = true;
177
- });
178
- } catch {
179
- }
180
- try {
181
- const result = await origAct(...actArgs);
182
- parentLogAction(session, {
183
- pageId,
184
- action: actMethod,
185
- source: "agent",
186
- selector: hint,
187
- value: actArgs[0] !== void 0 ? String(actArgs[0]).slice(0, 100) : void 0,
188
- duration: Date.now() - start,
189
- success: true
190
- });
191
- onActivity?.();
192
- return result;
193
- } catch (err) {
194
- parentLogAction(session, {
195
- pageId,
196
- action: actMethod,
197
- source: "agent",
198
- selector: hint,
199
- duration: Date.now() - start,
200
- success: false,
201
- error: err.message
202
- });
203
- onActivity?.();
204
- throw err;
205
- } finally {
206
- try {
207
- await page.evaluate(() => {
208
- window.__btApiActionInProgress = false;
209
- });
210
- } catch {
211
- }
212
- }
213
- };
214
- }
215
- for (const method of LOCATOR_RETURNING_METHODS) {
216
- if (typeof locator[method] !== "function") continue;
217
- const origMethod = locator[method].bind(locator);
218
- locator[method] = (...args) => {
219
- const child = origMethod(...args);
220
- const childHint = args.length > 0 ? `${hint}.${formatHint(method, args)}` : `${hint}.${method}()`;
221
- return wrapLocator(child, childHint, session, page, pageId, onActivity);
222
- };
223
- }
224
- if (typeof locator.nth === "function") {
225
- const origNth = locator.nth.bind(locator);
226
- locator.nth = (index) => {
227
- const child = origNth(index);
228
- const childHint = `${hint}.nth(${index})`;
229
- return wrapLocator(child, childHint, session, page, pageId, onActivity);
230
- };
231
- }
232
- if (typeof locator.all === "function") {
233
- const origAll = locator.all.bind(locator);
234
- locator.all = async () => {
235
- const items = await origAll();
236
- return items.map((item, i) => {
237
- const childHint = `${hint}.all()[${i}]`;
238
- return wrapLocator(item, childHint, session, page, pageId, onActivity);
239
- });
240
- };
241
- }
242
- return locator;
243
- }
244
- function wrapPageForActionLogging(page, session, pageId, onActivity) {
245
- const PAGE_ACTIONS = [
246
- "click",
247
- "dblclick",
248
- "fill",
249
- "type",
250
- "press",
251
- "check",
252
- "uncheck",
253
- "selectOption",
254
- "hover",
255
- "focus"
256
- ];
257
- const NAV_ACTIONS = ["goto", "reload", "goBack", "goForward"];
258
- for (const method of PAGE_ACTIONS) {
259
- const orig = page[method].bind(page);
260
- page[method] = async (...args) => {
261
- const start = Date.now();
262
- try {
263
- await page.evaluate(() => {
264
- window.__btApiActionInProgress = true;
265
- });
266
- } catch {
267
- }
268
- try {
269
- const result = await orig(...args);
270
- parentLogAction(session, {
271
- pageId,
272
- action: method,
273
- source: "agent",
274
- selector: typeof args[0] === "string" ? args[0] : void 0,
275
- value: args[1] !== void 0 ? String(args[1]).slice(0, 100) : void 0,
276
- duration: Date.now() - start,
277
- success: true
278
- });
279
- onActivity?.();
280
- return result;
281
- } catch (err) {
282
- parentLogAction(session, {
283
- pageId,
284
- action: method,
285
- source: "agent",
286
- selector: typeof args[0] === "string" ? args[0] : void 0,
287
- duration: Date.now() - start,
288
- success: false,
289
- error: err.message
290
- });
291
- onActivity?.();
292
- throw err;
293
- } finally {
294
- try {
295
- await page.evaluate(() => {
296
- window.__btApiActionInProgress = false;
297
- });
298
- } catch {
299
- }
300
- }
301
- };
302
- }
303
- for (const method of NAV_ACTIONS) {
304
- const orig = page[method].bind(page);
305
- page[method] = async (...args) => {
306
- const start = Date.now();
307
- try {
308
- const result = await orig(...args);
309
- parentLogAction(session, {
310
- pageId,
311
- action: method,
312
- source: "agent",
313
- url: typeof args[0] === "string" ? args[0] : page.url(),
314
- duration: Date.now() - start,
315
- success: true
316
- });
317
- onActivity?.();
318
- return result;
319
- } catch (err) {
320
- parentLogAction(session, {
321
- pageId,
322
- action: method,
323
- source: "agent",
324
- url: typeof args[0] === "string" ? args[0] : void 0,
325
- duration: Date.now() - start,
326
- success: false,
327
- error: err.message
328
- });
329
- onActivity?.();
330
- throw err;
331
- }
332
- };
333
- }
334
- const LOCATOR_FACTORIES = [
335
- "locator",
336
- "getByRole",
337
- "getByText",
338
- "getByLabel",
339
- "getByPlaceholder",
340
- "getByAltText",
341
- "getByTitle",
342
- "getByTestId"
343
- ];
344
- for (const factory of LOCATOR_FACTORIES) {
345
- const orig = page[factory].bind(page);
346
- page[factory] = (...factoryArgs) => {
347
- const locator = orig(...factoryArgs);
348
- const hint = formatHint(factory, factoryArgs);
349
- return wrapLocator(locator, hint, session, page, pageId, onActivity);
350
- };
351
- }
352
- }
353
- export {
354
- clearActionLog,
355
- clearNetworkLog,
356
- formatActionEntry,
357
- formatNetworkEntry,
358
- parentLogAction,
359
- readActionLog,
360
- readNetworkLog,
361
- wrapPageForActionLogging
362
- };
package/dist/cli/index.js DELETED
@@ -1,13 +0,0 @@
1
- import { runLibrettoCLI } from "./cli.js";
2
- import {
3
- maybeConfigureLLMClientFactoryFromEnv,
4
- setLLMClientFactory
5
- } from "./core/context.js";
6
- import { runClose } from "./commands/browser.js";
7
- maybeConfigureLLMClientFactoryFromEnv();
8
- void runLibrettoCLI();
9
- export {
10
- runClose,
11
- runLibrettoCLI,
12
- setLLMClientFactory
13
- };
@@ -1,227 +0,0 @@
1
- import { appendFileSync, existsSync, readFileSync } from "node:fs";
2
- import { writeFile } from "node:fs/promises";
3
- import { cwd } from "node:process";
4
- import { isAbsolute, resolve } from "node:path";
5
- import { pathToFileURL } from "node:url";
6
- import {
7
- launchBrowser
8
- } from "../../index.js";
9
- import { setSessionForPause } from "../../shared/debug/pause.js";
10
- import { parseSessionStateContent } from "../../shared/state/index.js";
11
- import { getProfilePath, normalizeDomain } from "../core/browser.js";
12
- import {
13
- getSessionActionsLogPath,
14
- getSessionNetworkLogPath,
15
- getSessionStatePath
16
- } from "../core/context.js";
17
- import { getPauseSignalPaths, removeSignalIfExists } from "../core/pause-signals.js";
18
- import { installSessionTelemetry } from "../core/session-telemetry.js";
19
- const LIBRETTO_WORKFLOW_BRAND = /* @__PURE__ */ Symbol.for("libretto.workflow");
20
- const FAILURE_HOLD_POLL_INTERVAL_MS = 250;
21
- function mirrorStdoutToFile(filePath) {
22
- const stdout = process.stdout;
23
- const originalWrite = stdout.write.bind(stdout);
24
- stdout.write = ((chunk, ...args) => {
25
- try {
26
- const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk), "utf8");
27
- appendFileSync(filePath, buffer);
28
- } catch {
29
- }
30
- return originalWrite(chunk, ...args);
31
- });
32
- return () => {
33
- stdout.write = originalWrite;
34
- };
35
- }
36
- function readSessionStatePid(session) {
37
- const statePath = getSessionStatePath(session);
38
- if (!existsSync(statePath)) return null;
39
- try {
40
- return parseSessionStateContent(readFileSync(statePath, "utf8"), statePath).pid;
41
- } catch {
42
- return null;
43
- }
44
- }
45
- async function waitForFailureSessionRelease(args) {
46
- const { session, expectedPid, logger } = args;
47
- logger.info("run-failure-session-hold", { session, expectedPid });
48
- while (true) {
49
- const currentPid = readSessionStatePid(session);
50
- if (currentPid !== expectedPid) {
51
- logger.info("run-failure-session-released", {
52
- session,
53
- expectedPid,
54
- currentPid
55
- });
56
- return;
57
- }
58
- await new Promise(
59
- (resolveWait) => setTimeout(resolveWait, FAILURE_HOLD_POLL_INTERVAL_MS)
60
- );
61
- }
62
- }
63
- function isLoadedLibrettoWorkflow(value) {
64
- if (!value || typeof value !== "object") return false;
65
- const candidate = value;
66
- return candidate[LIBRETTO_WORKFLOW_BRAND] === true && typeof candidate.run === "function" && !!candidate.metadata && typeof candidate.metadata === "object";
67
- }
68
- function resolveLocalAuthProfilePath(domain) {
69
- return getProfilePath(normalizeDomain(domain));
70
- }
71
- function getMissingLocalAuthProfileError(args) {
72
- const normalizedDomain = normalizeDomain(args.domain);
73
- return [
74
- `Local auth profile not found for domain "${normalizedDomain}".`,
75
- `Expected profile file: ${args.profilePath}`,
76
- "To create it:",
77
- ` 1. libretto-cli open https://${normalizedDomain} --headed --session ${args.session}`,
78
- " 2. Log in manually in the browser window.",
79
- ` 3. libretto-cli save ${normalizedDomain} --session ${args.session}`
80
- ].join("\n");
81
- }
82
- function getAbsoluteIntegrationPath(integrationPath) {
83
- const absolutePath = isAbsolute(integrationPath) ? integrationPath : resolve(cwd(), integrationPath);
84
- if (!existsSync(absolutePath)) {
85
- throw new Error(`Integration file does not exist: ${absolutePath}`);
86
- }
87
- return absolutePath;
88
- }
89
- async function loadWorkflowExport(absolutePath, exportName) {
90
- let loadedModule;
91
- try {
92
- loadedModule = await import(pathToFileURL(absolutePath).href);
93
- } catch (error) {
94
- throw new Error(
95
- `Failed to import integration module at ${absolutePath}: ${error instanceof Error ? error.message : String(error)}`
96
- );
97
- }
98
- const targetExport = loadedModule[exportName];
99
- if (!targetExport) {
100
- const availableExports = Object.keys(loadedModule);
101
- const detail = availableExports.length > 0 ? ` Available exports: ${availableExports.join(", ")}` : " The module has no exports.";
102
- throw new Error(
103
- `Export "${exportName}" was not found in ${absolutePath}.${detail}`
104
- );
105
- }
106
- if (!isLoadedLibrettoWorkflow(targetExport)) {
107
- throw new Error(
108
- [
109
- `Export "${exportName}" in ${absolutePath} is not a valid Libretto workflow.`,
110
- "",
111
- 'A workflow must be created using the workflow() function from "libretto":',
112
- "",
113
- ' import { workflow } from "libretto";',
114
- "",
115
- ` export const ${exportName} = workflow<InputType, OutputType>(`,
116
- " {},",
117
- " async (ctx, input) => {",
118
- " // ctx.page \u2014 Playwright Page instance",
119
- " // ctx.logger \u2014 MinimalLogger",
120
- " // ctx.services \u2014 injected dependencies (generic, default {})",
121
- " // input \u2014 JSON-serializable input matching InputType",
122
- " return output; // must match OutputType",
123
- " },",
124
- " );"
125
- ].join("\n")
126
- );
127
- }
128
- return targetExport;
129
- }
130
- async function runIntegrationInternal(args, options) {
131
- const { logger } = options;
132
- const absolutePath = getAbsoluteIntegrationPath(args.integrationPath);
133
- const workflow = await loadWorkflowExport(absolutePath, args.exportName);
134
- const signalPaths = getPauseSignalPaths(args.session);
135
- await removeSignalIfExists(signalPaths.pausedSignalPath);
136
- await removeSignalIfExists(signalPaths.resumeSignalPath);
137
- await removeSignalIfExists(signalPaths.completedSignalPath);
138
- await removeSignalIfExists(signalPaths.failedSignalPath);
139
- await removeSignalIfExists(signalPaths.outputSignalPath);
140
- const restoreStdout = mirrorStdoutToFile(signalPaths.outputSignalPath);
141
- console.log(
142
- `Running integration "${args.exportName}" from ${absolutePath} (${args.headless ? "headless" : "headed"})...`
143
- );
144
- const integrationLogger = logger.withScope("integration-run", {
145
- integrationPath: absolutePath,
146
- integrationExport: args.exportName,
147
- session: args.session
148
- });
149
- const authProfileDomain = args.authProfileDomain;
150
- const storageStatePath = authProfileDomain ? resolveLocalAuthProfilePath(authProfileDomain) : void 0;
151
- if (authProfileDomain && storageStatePath && !existsSync(storageStatePath)) {
152
- throw new Error(
153
- getMissingLocalAuthProfileError({
154
- domain: authProfileDomain,
155
- profilePath: storageStatePath,
156
- session: args.session
157
- })
158
- );
159
- }
160
- const browserSession = await launchBrowser({
161
- sessionName: args.session,
162
- headless: args.headless,
163
- storageStatePath
164
- });
165
- const actionsLogPath = getSessionActionsLogPath(args.session);
166
- const networkLogPath = getSessionNetworkLogPath(args.session);
167
- await installSessionTelemetry({
168
- context: browserSession.context,
169
- initialPage: browserSession.page,
170
- includeUserDomActions: true,
171
- logAction: (entry) => {
172
- appendFileSync(actionsLogPath, JSON.stringify(entry) + "\n");
173
- },
174
- logNetwork: (entry) => {
175
- appendFileSync(networkLogPath, JSON.stringify(entry) + "\n");
176
- }
177
- });
178
- setSessionForPause(args.session);
179
- const workflowContext = {
180
- logger: integrationLogger,
181
- page: browserSession.page,
182
- services: {}
183
- };
184
- try {
185
- try {
186
- await workflow.run(workflowContext, args.params ?? {});
187
- } catch (error) {
188
- const errorMessage = error instanceof Error ? error.message : String(error);
189
- await writeFile(
190
- signalPaths.failedSignalPath,
191
- JSON.stringify(
192
- {
193
- failedAt: (/* @__PURE__ */ new Date()).toISOString(),
194
- message: errorMessage
195
- },
196
- null,
197
- 2
198
- ),
199
- "utf8"
200
- );
201
- await waitForFailureSessionRelease({
202
- session: args.session,
203
- expectedPid: process.pid,
204
- logger
205
- });
206
- return { status: "failed-held" };
207
- }
208
- await writeFile(
209
- signalPaths.completedSignalPath,
210
- JSON.stringify({ completedAt: (/* @__PURE__ */ new Date()).toISOString() }, null, 2),
211
- "utf8"
212
- );
213
- console.log("Integration completed.");
214
- return { status: "completed" };
215
- } finally {
216
- restoreStdout();
217
- await browserSession.close();
218
- }
219
- }
220
- async function runIntegrationFromFileInWorker(args, logger) {
221
- return await runIntegrationInternal(args, {
222
- logger
223
- });
224
- }
225
- export {
226
- runIntegrationFromFileInWorker
227
- };
@@ -1,12 +0,0 @@
1
- import { z } from "zod";
2
- const RunIntegrationWorkerRequestSchema = z.object({
3
- integrationPath: z.string().min(1),
4
- exportName: z.string().min(1),
5
- session: z.string().min(1),
6
- params: z.unknown(),
7
- headless: z.boolean(),
8
- authProfileDomain: z.string().optional()
9
- });
10
- export {
11
- RunIntegrationWorkerRequestSchema
12
- };
@@ -1,66 +0,0 @@
1
- import { writeFile } from "node:fs/promises";
2
- import { ZodError } from "zod";
3
- import {
4
- RunIntegrationWorkerRequestSchema
5
- } from "./run-integration-worker-protocol.js";
6
- import { runIntegrationFromFileInWorker } from "./run-integration-runtime.js";
7
- import {
8
- ensureLibrettoSetup,
9
- withSessionLogger
10
- } from "../core/context.js";
11
- import { getPauseSignalPaths } from "../core/pause-signals.js";
12
- function parseWorkerRequest(argv) {
13
- const rawPayload = argv[2];
14
- if (!rawPayload) {
15
- throw new Error("Missing worker payload argument.");
16
- }
17
- let parsed;
18
- try {
19
- parsed = JSON.parse(rawPayload);
20
- } catch (error) {
21
- throw new Error(
22
- `Invalid worker payload JSON: ${error instanceof Error ? error.message : String(error)}`
23
- );
24
- }
25
- try {
26
- return RunIntegrationWorkerRequestSchema.parse(parsed);
27
- } catch (error) {
28
- if (error instanceof ZodError) {
29
- const details = error.issues.map((issue) => `${issue.path.join(".") || "root"}: ${issue.message}`).join("; ");
30
- throw new Error(`Worker payload is invalid: ${details}`);
31
- }
32
- throw error;
33
- }
34
- }
35
- async function main() {
36
- let request = null;
37
- let exitCode = 0;
38
- try {
39
- request = parseWorkerRequest(process.argv);
40
- const workerRequest = request;
41
- ensureLibrettoSetup();
42
- await withSessionLogger(workerRequest.session, async (logger) => {
43
- await runIntegrationFromFileInWorker(workerRequest, logger);
44
- });
45
- } catch (error) {
46
- const message = error instanceof Error ? error.message : String(error);
47
- if (request) {
48
- const { failedSignalPath } = getPauseSignalPaths(request.session);
49
- await writeFile(
50
- failedSignalPath,
51
- JSON.stringify(
52
- {
53
- failedAt: (/* @__PURE__ */ new Date()).toISOString(),
54
- message
55
- },
56
- null,
57
- 2
58
- ),
59
- "utf8"
60
- );
61
- }
62
- exitCode = 1;
63
- }
64
- process.exit(exitCode);
65
- }
66
- void main();