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,461 +0,0 @@
1
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
- import { spawn } from "node:child_process";
3
- import * as moduleBuiltin from "node:module";
4
- import { fileURLToPath } from "node:url";
5
- import { installInstrumentation } from "../../shared/instrumentation/index.js";
6
- import {
7
- connect,
8
- disconnectBrowser
9
- } from "../core/browser.js";
10
- import { getPauseSignalPaths } from "../core/pause-signals.js";
11
- import {
12
- assertSessionAvailableForStart,
13
- clearSessionState,
14
- readSessionState,
15
- readSessionStateOrThrow,
16
- setSessionStatus
17
- } from "../core/session.js";
18
- import {
19
- readActionLog,
20
- readNetworkLog,
21
- wrapPageForActionLogging
22
- } from "../core/telemetry.js";
23
- const stripTypeScriptTypes = moduleBuiltin.stripTypeScriptTypes;
24
- function withSuppressedStripTypeScriptWarning(action) {
25
- const mutableProcess = process;
26
- const originalEmitWarning = mutableProcess.emitWarning;
27
- mutableProcess.emitWarning = (...args) => {
28
- const warning = args[0];
29
- const typeOrOptions = args[1];
30
- const warningMessage = typeof warning === "string" ? warning : warning instanceof Error ? warning.message : "";
31
- const warningType = typeof typeOrOptions === "string" ? typeOrOptions : typeof typeOrOptions === "object" && typeOrOptions !== null && "type" in typeOrOptions && typeof typeOrOptions.type === "string" ? typeOrOptions.type ?? "" : "";
32
- if (warningType === "ExperimentalWarning" && warningMessage.includes("stripTypeScriptTypes")) {
33
- return;
34
- }
35
- originalEmitWarning(...args);
36
- };
37
- try {
38
- return action();
39
- } finally {
40
- mutableProcess.emitWarning = originalEmitWarning;
41
- }
42
- }
43
- function compileTypeScriptExecFunction(code, helperNames) {
44
- if (!stripTypeScriptTypes) return null;
45
- const wrappedSource = `(async function __librettoExec(${helperNames.join(", ")}) {
46
- ${code}
47
- })`;
48
- const jsSource = withSuppressedStripTypeScriptWarning(
49
- () => stripTypeScriptTypes(wrappedSource, { mode: "strip" })
50
- );
51
- const createFunction = new Function(
52
- `return ${jsSource}`
53
- );
54
- return createFunction();
55
- }
56
- function compileExecFunction(code, helperNames) {
57
- const typeStripped = compileTypeScriptExecFunction(code, helperNames);
58
- if (typeStripped) return typeStripped;
59
- const AsyncFunction = Object.getPrototypeOf(async function() {
60
- }).constructor;
61
- return new AsyncFunction(...helperNames, code);
62
- }
63
- async function runExec(code, session, logger, visualize = false, pageId) {
64
- readSessionStateOrThrow(session);
65
- logger.info("exec-start", {
66
- session,
67
- codeLength: code.length,
68
- codePreview: code.slice(0, 200),
69
- visualize,
70
- pageId
71
- });
72
- const { browser, context, page, pageId: resolvedPageId } = await connect(
73
- session,
74
- logger,
75
- 1e4,
76
- {
77
- pageId,
78
- requireSinglePage: true
79
- }
80
- );
81
- const STALL_THRESHOLD_MS = 6e4;
82
- let lastActivityTs = Date.now();
83
- const onActivity = () => {
84
- lastActivityTs = Date.now();
85
- };
86
- const stallInterval = setInterval(() => {
87
- const silenceMs = Date.now() - lastActivityTs;
88
- if (silenceMs >= STALL_THRESHOLD_MS) {
89
- logger.warn("exec-stall-warning", {
90
- session,
91
- silenceMs,
92
- codePreview: code.slice(0, 200)
93
- });
94
- console.warn(
95
- `[stall-warning] No Playwright activity for ${Math.round(silenceMs / 1e3)}s \u2014 exec may be hung (code: ${code.slice(0, 100)}...)`
96
- );
97
- }
98
- }, STALL_THRESHOLD_MS);
99
- const execStartTs = Date.now();
100
- const sigintHandler = () => {
101
- logger.info("exec-interrupted", {
102
- session,
103
- duration: Date.now() - execStartTs,
104
- codePreview: code.slice(0, 200)
105
- });
106
- };
107
- process.on("SIGINT", sigintHandler);
108
- wrapPageForActionLogging(page, session, resolvedPageId, onActivity);
109
- if (visualize) {
110
- await installInstrumentation(page, { visualize: true, logger });
111
- }
112
- try {
113
- const execState = {};
114
- const networkLog = (opts = {}) => {
115
- return readNetworkLog(session, opts);
116
- };
117
- const actionLog = (opts = {}) => {
118
- return readActionLog(session, opts);
119
- };
120
- const helpers = {
121
- page,
122
- context,
123
- state: execState,
124
- browser,
125
- networkLog,
126
- actionLog,
127
- console,
128
- setTimeout,
129
- setInterval,
130
- clearTimeout,
131
- clearInterval,
132
- fetch,
133
- URL,
134
- Buffer
135
- };
136
- const helperNames = Object.keys(helpers);
137
- const fn = compileExecFunction(code, helperNames);
138
- const result = await fn(...Object.values(helpers));
139
- logger.info("exec-success", { session, hasResult: result !== void 0 });
140
- if (result !== void 0) {
141
- console.log(
142
- typeof result === "string" ? result : JSON.stringify(result, null, 2)
143
- );
144
- }
145
- } catch (err) {
146
- logger.error("exec-error", {
147
- error: err,
148
- session,
149
- codePreview: code.slice(0, 200)
150
- });
151
- throw err;
152
- } finally {
153
- clearInterval(stallInterval);
154
- process.removeListener("SIGINT", sigintHandler);
155
- disconnectBrowser(browser, logger, session);
156
- }
157
- }
158
- function parseJsonArg(label, raw) {
159
- try {
160
- return JSON.parse(raw);
161
- } catch (error) {
162
- throw new Error(
163
- `Invalid JSON in ${label}: ${error instanceof Error ? error.message : String(error)}`
164
- );
165
- }
166
- }
167
- function isProcessRunning(pid) {
168
- try {
169
- process.kill(pid, 0);
170
- return true;
171
- } catch {
172
- return false;
173
- }
174
- }
175
- async function stopExistingFailedRunSession(session, logger) {
176
- const existingState = readSessionState(session, logger);
177
- if (!existingState || existingState.status !== "failed") {
178
- return;
179
- }
180
- logger.info("run-release-existing-failed-session", {
181
- session,
182
- pid: existingState.pid,
183
- port: existingState.port
184
- });
185
- clearSessionState(session, logger);
186
- const stopDeadline = Date.now() + 3e3;
187
- while (isProcessRunning(existingState.pid) && Date.now() < stopDeadline) {
188
- await new Promise((resolveWait) => setTimeout(resolveWait, 100));
189
- }
190
- if (isProcessRunning(existingState.pid)) {
191
- logger.warn("run-release-existing-failed-session-timeout", {
192
- session,
193
- pid: existingState.pid
194
- });
195
- console.warn(
196
- `Existing failed workflow process for session "${session}" (pid ${existingState.pid}) is still shutting down; continuing.`
197
- );
198
- return;
199
- }
200
- console.log(
201
- `Closed existing failed workflow process for session "${session}" (pid ${existingState.pid}).`
202
- );
203
- }
204
- function readJsonFileIfExists(path) {
205
- if (!existsSync(path)) return null;
206
- try {
207
- return JSON.parse(readFileSync(path, "utf8"));
208
- } catch {
209
- return null;
210
- }
211
- }
212
- function readFailureMessage(path) {
213
- const raw = readJsonFileIfExists(path);
214
- if (!raw || typeof raw !== "object") return null;
215
- const message = raw.message;
216
- return typeof message === "string" ? message : null;
217
- }
218
- async function waitForFailureMessage(path, timeoutMs = 1e3) {
219
- const deadline = Date.now() + timeoutMs;
220
- while (Date.now() < deadline) {
221
- const message = readFailureMessage(path);
222
- if (message) return message;
223
- await new Promise((resolveWait) => setTimeout(resolveWait, 25));
224
- }
225
- return readFailureMessage(path);
226
- }
227
- function streamOutputSince(path, offset) {
228
- if (!existsSync(path)) return offset;
229
- const output = readFileSync(path);
230
- if (output.length <= offset) return output.length;
231
- process.stdout.write(output.subarray(offset));
232
- return output.length;
233
- }
234
- function clearSignalIfExists(path) {
235
- if (!existsSync(path)) return;
236
- try {
237
- unlinkSync(path);
238
- } catch {
239
- }
240
- }
241
- async function waitForWorkflowOutcome(args) {
242
- const signalPaths = getPauseSignalPaths(args.session);
243
- if (args.pid <= 0) {
244
- return { status: "exited" };
245
- }
246
- let outputOffset = 0;
247
- while (true) {
248
- outputOffset = streamOutputSince(signalPaths.outputSignalPath, outputOffset);
249
- if (existsSync(signalPaths.failedSignalPath)) {
250
- outputOffset = streamOutputSince(signalPaths.outputSignalPath, outputOffset);
251
- const message = await waitForFailureMessage(signalPaths.failedSignalPath);
252
- return { status: "failed", message: message ?? void 0 };
253
- }
254
- if (existsSync(signalPaths.completedSignalPath)) {
255
- outputOffset = streamOutputSince(signalPaths.outputSignalPath, outputOffset);
256
- return { status: "completed" };
257
- }
258
- if (existsSync(signalPaths.pausedSignalPath)) {
259
- outputOffset = streamOutputSince(signalPaths.outputSignalPath, outputOffset);
260
- return { status: "paused" };
261
- }
262
- if (!isProcessRunning(args.pid)) {
263
- outputOffset = streamOutputSince(signalPaths.outputSignalPath, outputOffset);
264
- return { status: "exited" };
265
- }
266
- await new Promise((resolveWait) => setTimeout(resolveWait, 250));
267
- }
268
- }
269
- async function runResume(session, logger) {
270
- const state = readSessionStateOrThrow(session);
271
- const {
272
- pausedSignalPath,
273
- resumeSignalPath,
274
- completedSignalPath,
275
- failedSignalPath,
276
- outputSignalPath
277
- } = getPauseSignalPaths(session);
278
- if (!existsSync(pausedSignalPath)) {
279
- throw new Error(
280
- `Session "${session}" is not paused. Run "libretto-cli run ... --session ${session}" and call pause() first.`
281
- );
282
- }
283
- if (!isProcessRunning(state.pid)) {
284
- throw new Error(
285
- `No active paused workflow found for session "${session}" (worker pid ${state.pid} is not running).`
286
- );
287
- }
288
- clearSignalIfExists(pausedSignalPath);
289
- clearSignalIfExists(outputSignalPath);
290
- clearSignalIfExists(completedSignalPath);
291
- clearSignalIfExists(failedSignalPath);
292
- setSessionStatus(session, "active", logger);
293
- writeFileSync(
294
- resumeSignalPath,
295
- JSON.stringify(
296
- {
297
- resumedAt: (/* @__PURE__ */ new Date()).toISOString(),
298
- sourcePid: process.pid
299
- },
300
- null,
301
- 2
302
- ),
303
- "utf8"
304
- );
305
- console.log(`Resume signal sent for session "${session}".`);
306
- const outcome = await waitForWorkflowOutcome({
307
- session,
308
- pid: state.pid
309
- });
310
- if (outcome.status === "completed") {
311
- setSessionStatus(session, "completed", logger);
312
- console.log("Integration completed.");
313
- return;
314
- }
315
- if (outcome.status === "failed") {
316
- setSessionStatus(session, "failed", logger);
317
- throw new Error(
318
- outcome.message ? `Workflow failed after resume: ${outcome.message}` : "Workflow failed after resume."
319
- );
320
- }
321
- if (outcome.status === "exited") {
322
- setSessionStatus(session, "exited", logger);
323
- throw new Error(
324
- `Workflow process for session "${session}" exited before reporting completion or pause.`
325
- );
326
- }
327
- setSessionStatus(session, "paused", logger);
328
- console.log("Workflow paused.");
329
- }
330
- async function runIntegrationFromFile(args, logger) {
331
- await stopExistingFailedRunSession(args.session, logger);
332
- assertSessionAvailableForStart(args.session, logger);
333
- const signalPaths = getPauseSignalPaths(args.session);
334
- clearSignalIfExists(signalPaths.pausedSignalPath);
335
- clearSignalIfExists(signalPaths.resumeSignalPath);
336
- clearSignalIfExists(signalPaths.completedSignalPath);
337
- clearSignalIfExists(signalPaths.failedSignalPath);
338
- clearSignalIfExists(signalPaths.outputSignalPath);
339
- const workerEntryPath = fileURLToPath(
340
- new URL("../workers/run-integration-worker.js", import.meta.url)
341
- );
342
- const payload = JSON.stringify(args);
343
- const worker = spawn(process.execPath, [workerEntryPath, payload], {
344
- detached: true,
345
- stdio: "ignore",
346
- env: process.env
347
- });
348
- worker.unref();
349
- const outcome = await waitForWorkflowOutcome({
350
- session: args.session,
351
- pid: worker.pid ?? 0
352
- });
353
- if (outcome.status === "paused") {
354
- setSessionStatus(args.session, "paused", logger);
355
- console.log("Workflow paused.");
356
- return;
357
- }
358
- if (outcome.status === "failed") {
359
- setSessionStatus(args.session, "failed", logger);
360
- throw new Error(
361
- `${outcome.message ?? "Workflow failed during run."}
362
- Browser is still open. You can use \`exec\` to inspect it. Call \`run\` to re-run the workflow.`
363
- );
364
- }
365
- if (outcome.status === "exited") {
366
- setSessionStatus(args.session, "exited", logger);
367
- throw new Error(
368
- "Workflow process exited before reporting completion or pause during run."
369
- );
370
- }
371
- setSessionStatus(args.session, "completed", logger);
372
- }
373
- function registerExecutionCommands(yargs, logger) {
374
- return yargs.command(
375
- "exec [code..]",
376
- "Execute Playwright TypeScript code",
377
- (cmd) => cmd.option("visualize", { type: "boolean", default: false }).option("page", { type: "string" }),
378
- async (argv) => {
379
- const codeParts = Array.isArray(argv.code) ? argv.code : argv.code ? [String(argv.code)] : [];
380
- const code = codeParts.join(" ");
381
- if (!code) {
382
- throw new Error(
383
- "Usage: libretto-cli exec <code> [--session <name>] [--visualize]"
384
- );
385
- }
386
- await runExec(
387
- code,
388
- String(argv.session),
389
- logger,
390
- Boolean(argv.visualize),
391
- argv.page ? String(argv.page) : void 0
392
- );
393
- }
394
- ).command(
395
- "run [integrationFile] [integrationExport]",
396
- "Run an exported Libretto workflow from a file",
397
- (cmd) => cmd.option("params", { type: "string" }).option("params-file", { type: "string" }).option("headed", { type: "boolean", default: false }).option("headless", { type: "boolean", default: false }).option("auth-profile", { type: "string", describe: "Domain for local auth profile (e.g. apps.example.com)" }),
398
- async (argv) => {
399
- const usage = "Usage: libretto-cli run <integrationFile> <integrationExport> [--params <json> | --params-file <path>] [--headed|--headless]";
400
- const integrationPath = argv.integrationFile;
401
- const exportName = argv.integrationExport;
402
- const legacyDebug = argv.debug;
403
- if (legacyDebug !== void 0) {
404
- throw new Error(
405
- "The --debug flag has been removed. Run the command without --debug."
406
- );
407
- }
408
- if (!integrationPath || !exportName) {
409
- throw new Error(usage);
410
- }
411
- const session = String(argv.session);
412
- const rawInlineParams = argv.params;
413
- const paramsFile = argv["params-file"];
414
- if (rawInlineParams && paramsFile) {
415
- throw new Error("Pass either --params or --params-file, not both.");
416
- }
417
- const params = (() => {
418
- if (paramsFile) {
419
- let content;
420
- try {
421
- content = readFileSync(paramsFile, "utf8");
422
- } catch {
423
- throw new Error(
424
- `Could not read --params-file "${paramsFile}". Ensure the file exists and is readable.`
425
- );
426
- }
427
- return parseJsonArg("--params-file", content);
428
- }
429
- if (rawInlineParams) {
430
- return parseJsonArg("--params", rawInlineParams);
431
- }
432
- return {};
433
- })();
434
- const hasHeadedFlag = Boolean(argv.headed);
435
- const hasHeadlessFlag = Boolean(argv.headless);
436
- if (hasHeadedFlag && hasHeadlessFlag) {
437
- throw new Error("Cannot pass both --headed and --headless.");
438
- }
439
- const headlessMode = hasHeadedFlag ? false : hasHeadlessFlag ? true : void 0;
440
- const authProfileDomain = argv["auth-profile"];
441
- await runIntegrationFromFile({
442
- integrationPath,
443
- exportName,
444
- session,
445
- params,
446
- headless: headlessMode ?? false,
447
- authProfileDomain
448
- }, logger);
449
- }
450
- ).command(
451
- "resume",
452
- "Resume a paused workflow for the current session",
453
- (cmd) => cmd,
454
- async (argv) => {
455
- await runResume(String(argv.session), logger);
456
- }
457
- );
458
- }
459
- export {
460
- registerExecutionCommands
461
- };
@@ -1,95 +0,0 @@
1
- import { existsSync, mkdirSync, cpSync, readdirSync } from "node:fs";
2
- import { join, dirname } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { spawnSync } from "node:child_process";
5
- import { REPO_ROOT } from "../core/context.js";
6
- function getSkillSourceDir() {
7
- const thisDir = dirname(fileURLToPath(import.meta.url));
8
- const pkgRoot = join(thisDir, "..", "..", "..");
9
- const skillDir = join(pkgRoot, "skill");
10
- if (existsSync(skillDir)) return skillDir;
11
- const skillsDir = join(pkgRoot, "skills");
12
- if (existsSync(skillsDir)) return skillsDir;
13
- throw new Error(
14
- "Could not find skill/ or skills/ directory in the libretto package."
15
- );
16
- }
17
- function copySkills() {
18
- const src = getSkillSourceDir();
19
- const files = readdirSync(src);
20
- if (files.length === 0) {
21
- console.log(" No skill files found to copy.");
22
- return;
23
- }
24
- const targets = [
25
- join(REPO_ROOT, ".agents", "skills", "libretto"),
26
- join(REPO_ROOT, ".claude", "skills", "libretto")
27
- ];
28
- for (const target of targets) {
29
- mkdirSync(target, { recursive: true });
30
- cpSync(src, target, { recursive: true });
31
- console.log(` \u2713 Copied skill files to ${target}`);
32
- }
33
- }
34
- function installBrowsers() {
35
- console.log("\nInstalling Playwright Chromium...");
36
- const result = spawnSync("npx", ["playwright", "install", "chromium"], {
37
- stdio: "inherit",
38
- shell: true
39
- });
40
- if (result.status === 0) {
41
- console.log(" \u2713 Playwright Chromium installed");
42
- } else {
43
- console.error(
44
- " \u2717 Failed to install Playwright Chromium. Run manually: npx playwright install chromium"
45
- );
46
- }
47
- }
48
- function checkSnapshotLLM() {
49
- const hasAnyCreds = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
50
- console.log("\nSnapshot LLM configuration:");
51
- if (hasAnyCreds) {
52
- console.log(" \u2713 LLM credentials detected");
53
- } else {
54
- console.log(" \u2717 No LLM credentials found.");
55
- console.log(" Set one of the following environment variables:");
56
- console.log(" GOOGLE_CLOUD_PROJECT (for Vertex AI / Gemini)");
57
- console.log(" ANTHROPIC_API_KEY (for Claude)");
58
- console.log(" OPENAI_API_KEY (for GPT)");
59
- console.log(
60
- " Then configure via: npx libretto ai configure <preset>"
61
- );
62
- }
63
- }
64
- function registerInitCommand(yargs) {
65
- return yargs.command(
66
- "init",
67
- "Initialize libretto in the current project",
68
- (cmd) => cmd.option("skip-browsers", {
69
- type: "boolean",
70
- default: false,
71
- describe: "Skip Playwright Chromium installation"
72
- }),
73
- (argv) => {
74
- console.log("Initializing libretto...\n");
75
- console.log("Copying skill files...");
76
- try {
77
- copySkills();
78
- } catch (err) {
79
- console.error(
80
- ` \u2717 ${err instanceof Error ? err.message : String(err)}`
81
- );
82
- }
83
- if (!argv["skip-browsers"]) {
84
- installBrowsers();
85
- } else {
86
- console.log("\nSkipping browser installation (--skip-browsers)");
87
- }
88
- checkSnapshotLLM();
89
- console.log("\n\u2713 libretto init complete");
90
- }
91
- );
92
- }
93
- export {
94
- registerInitCommand
95
- };
@@ -1,93 +0,0 @@
1
- import { listOpenPages } from "../core/browser.js";
2
- import { withSessionLogger } from "../core/context.js";
3
- import {
4
- clearActionLog,
5
- clearNetworkLog,
6
- formatActionEntry,
7
- formatNetworkEntry,
8
- readActionLog,
9
- readNetworkLog
10
- } from "../core/telemetry.js";
11
- async function resolvePageId(session, pageId) {
12
- if (!pageId) return void 0;
13
- const pages = await withSessionLogger(
14
- session,
15
- async (logger) => listOpenPages(session, logger)
16
- );
17
- const foundPage = pages.find((page) => page.id === pageId);
18
- if (!foundPage) {
19
- throw new Error(
20
- `Page "${pageId}" was not found in session "${session}". Run "libretto-cli pages --session ${session}" to list ids.`
21
- );
22
- }
23
- return pageId;
24
- }
25
- function registerLogCommands(yargs) {
26
- return yargs.command(
27
- "network",
28
- "View captured network requests",
29
- (cmd) => cmd.option("last", { type: "number" }).option("filter", { type: "string" }).option("method", { type: "string" }).option("page", { type: "string" }).option("clear", { type: "boolean", default: false }),
30
- async (argv) => {
31
- const session = String(argv.session);
32
- if (argv.clear) {
33
- clearNetworkLog(session);
34
- console.log("Network log cleared.");
35
- return;
36
- }
37
- const pageId = await resolvePageId(
38
- session,
39
- argv.page ? String(argv.page) : void 0
40
- );
41
- const entries = readNetworkLog(session, {
42
- last: typeof argv.last === "number" ? argv.last : void 0,
43
- filter: argv.filter,
44
- method: argv.method,
45
- pageId
46
- });
47
- if (entries.length === 0) {
48
- console.log("No network requests captured.");
49
- return;
50
- }
51
- for (const entry of entries) {
52
- console.log(formatNetworkEntry(entry));
53
- }
54
- console.log(`
55
- ${entries.length} request(s) shown.`);
56
- }
57
- ).command(
58
- "actions",
59
- "View captured actions",
60
- (cmd) => cmd.option("last", { type: "number" }).option("filter", { type: "string" }).option("action", { type: "string" }).option("source", { type: "string" }).option("page", { type: "string" }).option("clear", { type: "boolean", default: false }),
61
- async (argv) => {
62
- const session = String(argv.session);
63
- if (argv.clear) {
64
- clearActionLog(session);
65
- console.log("Action log cleared.");
66
- return;
67
- }
68
- const pageId = await resolvePageId(
69
- session,
70
- argv.page ? String(argv.page) : void 0
71
- );
72
- const entries = readActionLog(session, {
73
- last: typeof argv.last === "number" ? argv.last : void 0,
74
- filter: argv.filter,
75
- action: argv.action,
76
- source: argv.source,
77
- pageId
78
- });
79
- if (entries.length === 0) {
80
- console.log("No actions captured.");
81
- return;
82
- }
83
- for (const entry of entries) {
84
- console.log(formatActionEntry(entry));
85
- }
86
- console.log(`
87
- ${entries.length} action(s) shown.`);
88
- }
89
- );
90
- }
91
- export {
92
- registerLogCommands
93
- };