libretto 0.2.3 → 0.2.5

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 (42) hide show
  1. package/README.md +78 -184
  2. package/dist/cli/cli.js +8 -2
  3. package/dist/cli/commands/browser.js +26 -3
  4. package/dist/cli/commands/execution.js +50 -11
  5. package/dist/cli/commands/init.js +95 -0
  6. package/dist/cli/core/browser.js +131 -6
  7. package/dist/cli/core/context.js +5 -0
  8. package/dist/cli/core/session.js +13 -13
  9. package/dist/cli/workers/run-integration-runtime.js +64 -59
  10. package/dist/cli/workers/run-integration-worker-protocol.js +12 -0
  11. package/dist/cli/workers/run-integration-worker.js +13 -30
  12. package/dist/index.cjs +5 -12
  13. package/dist/index.d.cts +4 -2
  14. package/dist/index.d.ts +4 -2
  15. package/dist/index.js +5 -15
  16. package/dist/shared/debug/index.cjs +4 -6
  17. package/dist/shared/debug/index.d.cts +1 -2
  18. package/dist/shared/debug/index.d.ts +1 -2
  19. package/dist/shared/debug/index.js +3 -8
  20. package/dist/shared/debug/pause.cjs +58 -24
  21. package/dist/shared/debug/pause.d.cts +13 -20
  22. package/dist/shared/debug/pause.d.ts +13 -20
  23. package/dist/shared/debug/pause.js +46 -21
  24. package/dist/shared/llm/ai-sdk-adapter.cjs +67 -0
  25. package/dist/shared/llm/ai-sdk-adapter.d.cts +22 -0
  26. package/dist/shared/llm/ai-sdk-adapter.d.ts +22 -0
  27. package/dist/shared/llm/ai-sdk-adapter.js +43 -0
  28. package/dist/shared/llm/index.cjs +5 -2
  29. package/dist/shared/llm/index.d.cts +2 -0
  30. package/dist/shared/llm/index.d.ts +2 -0
  31. package/dist/shared/llm/index.js +3 -1
  32. package/dist/shared/llm/types.d.cts +32 -0
  33. package/dist/shared/llm/types.d.ts +32 -0
  34. package/dist/shared/run/api.cjs +0 -7
  35. package/dist/shared/run/api.d.cts +0 -1
  36. package/dist/shared/run/api.d.ts +0 -1
  37. package/dist/shared/run/api.js +0 -8
  38. package/dist/shared/workflow/workflow.d.cts +11 -24
  39. package/dist/shared/workflow/workflow.d.ts +11 -24
  40. package/package.json +4 -10
  41. package/skill/SKILL.md +18 -5
  42. package/skill/code-generation-rules.md +7 -10
@@ -12,12 +12,15 @@ import {
12
12
  import {
13
13
  assertSessionAvailableForStart,
14
14
  clearSessionState,
15
+ listSessionsWithStateFile,
15
16
  readSessionStateOrThrow,
16
17
  logFileForSession,
17
18
  readSessionState,
18
19
  writeSessionState
19
20
  } from "./session.js";
20
21
  import { installSessionTelemetry } from "./session-telemetry.js";
22
+ const CLOSE_WAIT_MS = 1500;
23
+ const FORCE_CLOSE_WAIT_MS = 300;
21
24
  async function pickFreePort() {
22
25
  return await new Promise((resolve2, reject) => {
23
26
  const server = createServer();
@@ -488,16 +491,137 @@ async function runClose(session, logger) {
488
491
  return;
489
492
  }
490
493
  logger.info("close-killing", { session, pid: state.pid, port: state.port });
491
- try {
492
- process.kill(state.pid, "SIGTERM");
493
- } catch (err) {
494
- logger.warn("close-kill-failed", { error: err, session, pid: state.pid });
495
- }
496
- await new Promise((r) => setTimeout(r, 1500));
494
+ sendSignalToProcessGroupOrPid(state.pid, "SIGTERM", logger, session);
495
+ await waitForCloseSignalWindow(CLOSE_WAIT_MS);
497
496
  clearSessionState(session, logger);
498
497
  logger.info("close-success", { session });
499
498
  console.log(`Browser closed (session: ${session}).`);
500
499
  }
500
+ function waitForCloseSignalWindow(ms) {
501
+ return new Promise((r) => setTimeout(r, ms));
502
+ }
503
+ function isPidRunning(pid) {
504
+ try {
505
+ process.kill(pid, 0);
506
+ return true;
507
+ } catch {
508
+ return false;
509
+ }
510
+ }
511
+ function sendSignalToProcessGroupOrPid(pid, signal, logger, session) {
512
+ try {
513
+ process.kill(pid, signal);
514
+ logger.info("close-signal-pid", { session, pid, signal });
515
+ } catch (pidErr) {
516
+ const pidCode = pidErr.code;
517
+ if (pidCode !== "ESRCH") {
518
+ logger.warn("close-signal-pid-failed", {
519
+ session,
520
+ pid,
521
+ signal,
522
+ error: pidErr
523
+ });
524
+ }
525
+ }
526
+ }
527
+ function formatSessionList(targets) {
528
+ return targets.map((target) => `"${target.session}"`).join(", ");
529
+ }
530
+ function resolveClosableSessions(logger) {
531
+ const sessions = listSessionsWithStateFile();
532
+ const closable = [];
533
+ let clearedUnreadableStates = 0;
534
+ for (const session of sessions) {
535
+ const state = readSessionState(session, logger);
536
+ if (!state) {
537
+ clearSessionState(session, logger);
538
+ clearedUnreadableStates += 1;
539
+ continue;
540
+ }
541
+ closable.push({
542
+ session,
543
+ pid: state.pid,
544
+ port: state.port
545
+ });
546
+ }
547
+ return { closable, clearedUnreadableStates };
548
+ }
549
+ function clearStoppedSessionStates(sessions, logger) {
550
+ let cleared = 0;
551
+ for (const session of sessions) {
552
+ if (!isPidRunning(session.pid)) {
553
+ clearSessionState(session.session, logger);
554
+ cleared += 1;
555
+ }
556
+ }
557
+ return cleared;
558
+ }
559
+ async function runCloseAll(logger, options) {
560
+ const force = Boolean(options?.force);
561
+ logger.info("close-all-start", { force });
562
+ const { closable, clearedUnreadableStates } = resolveClosableSessions(logger);
563
+ if (closable.length === 0) {
564
+ if (clearedUnreadableStates > 0) {
565
+ console.log(
566
+ `Cleared ${clearedUnreadableStates} unreadable session state file(s).`
567
+ );
568
+ }
569
+ console.log("No browser sessions found.");
570
+ return;
571
+ }
572
+ for (const target of closable) {
573
+ logger.info("close-all-sigterm", {
574
+ session: target.session,
575
+ pid: target.pid,
576
+ port: target.port
577
+ });
578
+ sendSignalToProcessGroupOrPid(target.pid, "SIGTERM", logger, target.session);
579
+ }
580
+ await waitForCloseSignalWindow(CLOSE_WAIT_MS);
581
+ let survivors = closable.filter((target) => isPidRunning(target.pid));
582
+ if (survivors.length > 0 && !force) {
583
+ const closed = clearStoppedSessionStates(closable, logger);
584
+ throw new Error(
585
+ [
586
+ `Failed to close ${survivors.length} session(s) gracefully: ${formatSessionList(survivors)}.`,
587
+ `Closed ${closed} session(s).`,
588
+ "Retry with: libretto-cli close --all --force"
589
+ ].join("\n")
590
+ );
591
+ }
592
+ let forceKilled = 0;
593
+ if (survivors.length > 0) {
594
+ for (const survivor of survivors) {
595
+ logger.warn("close-all-sigkill", {
596
+ session: survivor.session,
597
+ pid: survivor.pid
598
+ });
599
+ sendSignalToProcessGroupOrPid(survivor.pid, "SIGKILL", logger, survivor.session);
600
+ forceKilled += 1;
601
+ }
602
+ await waitForCloseSignalWindow(FORCE_CLOSE_WAIT_MS);
603
+ survivors = survivors.filter((target) => isPidRunning(target.pid));
604
+ if (survivors.length > 0) {
605
+ const closed = clearStoppedSessionStates(closable, logger);
606
+ throw new Error(
607
+ [
608
+ `Failed to force-close ${survivors.length} session(s): ${formatSessionList(survivors)}.`,
609
+ `Closed ${closed} session(s).`
610
+ ].join("\n")
611
+ );
612
+ }
613
+ }
614
+ clearStoppedSessionStates(closable, logger);
615
+ if (clearedUnreadableStates > 0) {
616
+ console.log(
617
+ `Cleared ${clearedUnreadableStates} unreadable session state file(s).`
618
+ );
619
+ }
620
+ console.log(`Closed ${closable.length} session(s).`);
621
+ if (forceKilled > 0) {
622
+ console.log(`Force-killed ${forceKilled} session(s).`);
623
+ }
624
+ }
501
625
  function resolvePath(filePath) {
502
626
  return join(process.cwd(), filePath);
503
627
  }
@@ -517,6 +641,7 @@ export {
517
641
  normalizeUrl,
518
642
  resolvePath,
519
643
  runClose,
644
+ runCloseAll,
520
645
  runOpen,
521
646
  runPages,
522
647
  runSave
@@ -53,6 +53,11 @@ function ensureLibrettoSetup() {
53
53
  if (!existsSync(LIBRETTO_GITIGNORE_PATH)) {
54
54
  writeFileSync(LIBRETTO_GITIGNORE_PATH, LIBRETTO_GITIGNORE_CONTENT, "utf-8");
55
55
  }
56
+ const agentsSkillsDir = join(REPO_ROOT, ".agents", "skills", "libretto");
57
+ const claudeSkillsDir = join(REPO_ROOT, ".claude", "skills", "libretto");
58
+ if (!existsSync(agentsSkillsDir) && !existsSync(claudeSkillsDir)) {
59
+ console.log("[libretto] Skills not installed. Run 'npx libretto init' to complete setup.");
60
+ }
56
61
  }
57
62
  function createLoggerForSession(session) {
58
63
  validateSessionName(session);
@@ -14,7 +14,6 @@ import {
14
14
  } from "./context.js";
15
15
  import {
16
16
  SESSION_STATE_VERSION,
17
- SessionStatusSchema,
18
17
  parseSessionStateContent,
19
18
  serializeSessionState
20
19
  } from "../../shared/state/index.js";
@@ -65,11 +64,19 @@ function readSessionState(session, logger) {
65
64
  return null;
66
65
  }
67
66
  }
68
- function listActiveSessions() {
67
+ function listSessionsWithStateFile() {
69
68
  if (!existsSync(LIBRETTO_SESSIONS_DIR)) return [];
70
- return readdirSync(LIBRETTO_SESSIONS_DIR).filter(
71
- (session) => existsSync(getSessionStatePath(session))
72
- );
69
+ return readdirSync(LIBRETTO_SESSIONS_DIR).filter((session) => {
70
+ try {
71
+ validateSessionName(session);
72
+ } catch {
73
+ return false;
74
+ }
75
+ return existsSync(getSessionStatePath(session));
76
+ }).sort();
77
+ }
78
+ function listActiveSessions() {
79
+ return listSessionsWithStateFile();
73
80
  }
74
81
  function throwSessionNotFoundError(session) {
75
82
  const active = listActiveSessions();
@@ -128,9 +135,6 @@ function clearSessionState(session, logger) {
128
135
  unlinkSync(stateFile);
129
136
  logger?.info("session-state-cleared", { session, stateFile });
130
137
  }
131
- function isSessionStatus(value) {
132
- return SessionStatusSchema.safeParse(value).success;
133
- }
134
138
  function isPidRunning(pid) {
135
139
  try {
136
140
  process.kill(pid, 0);
@@ -151,11 +155,6 @@ function setSessionStatus(session, status, logger) {
151
155
  function assertSessionAvailableForStart(session, logger) {
152
156
  const existingState = readSessionState(session, logger);
153
157
  if (!existingState) return;
154
- if (isSessionStatus(existingState.status)) {
155
- if (existingState.status === "completed" || existingState.status === "failed" || existingState.status === "exited") {
156
- return;
157
- }
158
- }
159
158
  if (!isPidRunning(existingState.pid)) {
160
159
  setSessionStatus(session, "exited", logger);
161
160
  return;
@@ -174,6 +173,7 @@ export {
174
173
  assertSessionStateExistsOrThrow,
175
174
  clearSessionState,
176
175
  getStateFilePath,
176
+ listSessionsWithStateFile,
177
177
  logFileForSession,
178
178
  readSessionState,
179
179
  readSessionStateOrThrow,
@@ -1,21 +1,23 @@
1
- import { appendFileSync, existsSync } from "node:fs";
2
- import { mkdir, writeFile } from "node:fs/promises";
1
+ import { appendFileSync, existsSync, readFileSync } from "node:fs";
2
+ import { writeFile } from "node:fs/promises";
3
3
  import { cwd } from "node:process";
4
4
  import { isAbsolute, resolve } from "node:path";
5
5
  import { pathToFileURL } from "node:url";
6
6
  import {
7
7
  launchBrowser
8
8
  } from "../../index.js";
9
+ import { setSessionForPause } from "../../shared/debug/pause.js";
10
+ import { parseSessionStateContent } from "../../shared/state/index.js";
9
11
  import { getProfilePath, normalizeDomain } from "../core/browser.js";
10
12
  import {
11
13
  getSessionActionsLogPath,
12
- getSessionDir,
13
- getSessionNetworkLogPath
14
+ getSessionNetworkLogPath,
15
+ getSessionStatePath
14
16
  } from "../core/context.js";
15
17
  import { getPauseSignalPaths, removeSignalIfExists } from "../core/pause-signals.js";
16
18
  import { installSessionTelemetry } from "../core/session-telemetry.js";
17
19
  const LIBRETTO_WORKFLOW_BRAND = /* @__PURE__ */ Symbol.for("libretto.workflow");
18
- const RESUME_POLL_INTERVAL_MS = 250;
20
+ const FAILURE_HOLD_POLL_INTERVAL_MS = 250;
19
21
  function mirrorStdoutToFile(filePath) {
20
22
  const stdout = process.stdout;
21
23
  const originalWrite = stdout.write.bind(stdout);
@@ -31,23 +33,32 @@ function mirrorStdoutToFile(filePath) {
31
33
  stdout.write = originalWrite;
32
34
  };
33
35
  }
34
- async function waitForResumeSignal(args) {
35
- const { pausedSignalPath, resumeSignalPath } = args.signalPaths;
36
- await mkdir(getSessionDir(args.session), { recursive: true });
37
- await removeSignalIfExists(resumeSignalPath);
38
- await writeFile(
39
- pausedSignalPath,
40
- JSON.stringify(args.details, null, 2),
41
- "utf8"
42
- );
43
- await args.onPaused?.(args.details);
44
- while (!existsSync(resumeSignalPath)) {
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
+ }
45
58
  await new Promise(
46
- (resolveWait) => setTimeout(resolveWait, RESUME_POLL_INTERVAL_MS)
59
+ (resolveWait) => setTimeout(resolveWait, FAILURE_HOLD_POLL_INTERVAL_MS)
47
60
  );
48
61
  }
49
- await removeSignalIfExists(resumeSignalPath);
50
- await removeSignalIfExists(pausedSignalPath);
51
62
  }
52
63
  function isLoadedLibrettoWorkflow(value) {
53
64
  if (!value || typeof value !== "object") return false;
@@ -57,13 +68,6 @@ function isLoadedLibrettoWorkflow(value) {
57
68
  function resolveLocalAuthProfilePath(domain) {
58
69
  return getProfilePath(normalizeDomain(domain));
59
70
  }
60
- function resolveWorkflowStorageStatePath(workflow) {
61
- const authProfile = workflow.metadata.authProfile;
62
- if (authProfile?.type !== "local") {
63
- return void 0;
64
- }
65
- return resolveLocalAuthProfilePath(authProfile.domain);
66
- }
67
71
  function getMissingLocalAuthProfileError(args) {
68
72
  const normalizedDomain = normalizeDomain(args.domain);
69
73
  return [
@@ -101,7 +105,24 @@ async function loadWorkflowExport(absolutePath, exportName) {
101
105
  }
102
106
  if (!isLoadedLibrettoWorkflow(targetExport)) {
103
107
  throw new Error(
104
- `Export "${exportName}" in ${absolutePath} must be a Libretto workflow instance. Use workflow(...) from "libretto".`
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")
105
126
  );
106
127
  }
107
128
  return targetExport;
@@ -125,12 +146,12 @@ async function runIntegrationInternal(args, options) {
125
146
  integrationExport: args.exportName,
126
147
  session: args.session
127
148
  });
128
- const authProfile = workflow.metadata.authProfile;
129
- const storageStatePath = resolveWorkflowStorageStatePath(workflow);
130
- if (authProfile?.type === "local" && storageStatePath && !existsSync(storageStatePath)) {
149
+ const authProfileDomain = args.authProfileDomain;
150
+ const storageStatePath = authProfileDomain ? resolveLocalAuthProfilePath(authProfileDomain) : void 0;
151
+ if (authProfileDomain && storageStatePath && !existsSync(storageStatePath)) {
131
152
  throw new Error(
132
153
  getMissingLocalAuthProfileError({
133
- domain: authProfile.domain,
154
+ domain: authProfileDomain,
134
155
  profilePath: storageStatePath,
135
156
  session: args.session
136
157
  })
@@ -154,50 +175,35 @@ async function runIntegrationInternal(args, options) {
154
175
  appendFileSync(networkLogPath, JSON.stringify(entry) + "\n");
155
176
  }
156
177
  });
178
+ setSessionForPause(args.session);
157
179
  const workflowContext = {
158
180
  logger: integrationLogger,
159
181
  page: browserSession.page,
160
- context: browserSession.context,
161
- browser: browserSession.browser,
162
- session: args.session,
163
- integrationPath: absolutePath,
164
- exportName: args.exportName,
165
- headless: args.headless,
166
- debug: args.debug,
167
- pause: async () => {
168
- const details = {
169
- sessionName: args.session,
170
- pausedAt: (/* @__PURE__ */ new Date()).toISOString(),
171
- url: browserSession.page.url()
172
- };
173
- console.log(`[pause] Paused at ${details.url}`);
174
- console.log("[pause] Waiting for resume signal...");
175
- await waitForResumeSignal({
176
- signalPaths,
177
- session: args.session,
178
- details,
179
- onPaused: options.onPaused
180
- });
181
- console.log("[pause] Resume signal received. Continuing workflow...");
182
- }
182
+ services: {}
183
183
  };
184
184
  try {
185
185
  try {
186
186
  await workflow.run(workflowContext, args.params ?? {});
187
187
  } catch (error) {
188
+ const errorMessage = error instanceof Error ? error.message : String(error);
188
189
  await writeFile(
189
190
  signalPaths.failedSignalPath,
190
191
  JSON.stringify(
191
192
  {
192
193
  failedAt: (/* @__PURE__ */ new Date()).toISOString(),
193
- message: error instanceof Error ? error.message : String(error)
194
+ message: errorMessage
194
195
  },
195
196
  null,
196
197
  2
197
198
  ),
198
199
  "utf8"
199
200
  );
200
- throw error;
201
+ await waitForFailureSessionRelease({
202
+ session: args.session,
203
+ expectedPid: process.pid,
204
+ logger
205
+ });
206
+ return { status: "failed-held" };
201
207
  }
202
208
  await writeFile(
203
209
  signalPaths.completedSignalPath,
@@ -211,10 +217,9 @@ async function runIntegrationInternal(args, options) {
211
217
  await browserSession.close();
212
218
  }
213
219
  }
214
- async function runIntegrationFromFileInWorker(args, logger, onPaused) {
220
+ async function runIntegrationFromFileInWorker(args, logger) {
215
221
  return await runIntegrationInternal(args, {
216
- logger,
217
- onPaused
222
+ logger
218
223
  });
219
224
  }
220
225
  export {
@@ -0,0 +1,12 @@
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,17 +1,14 @@
1
1
  import { writeFile } from "node:fs/promises";
2
+ import { ZodError } from "zod";
3
+ import {
4
+ RunIntegrationWorkerRequestSchema
5
+ } from "./run-integration-worker-protocol.js";
2
6
  import { runIntegrationFromFileInWorker } from "./run-integration-runtime.js";
3
7
  import {
4
8
  ensureLibrettoSetup,
5
9
  withSessionLogger
6
10
  } from "../core/context.js";
7
11
  import { getPauseSignalPaths } from "../core/pause-signals.js";
8
- function sendMessage(message) {
9
- if (typeof process.send !== "function" || !process.connected) return;
10
- try {
11
- process.send(message);
12
- } catch {
13
- }
14
- }
15
12
  function parseWorkerRequest(argv) {
16
13
  const rawPayload = argv[2];
17
14
  if (!rawPayload) {
@@ -25,21 +22,15 @@ function parseWorkerRequest(argv) {
25
22
  `Invalid worker payload JSON: ${error instanceof Error ? error.message : String(error)}`
26
23
  );
27
24
  }
28
- if (!parsed || typeof parsed !== "object") {
29
- throw new Error("Worker payload must be an object.");
30
- }
31
- const candidate = parsed;
32
- if (typeof candidate.integrationPath !== "string" || typeof candidate.exportName !== "string" || typeof candidate.session !== "string" || typeof candidate.headless !== "boolean" || typeof candidate.debug !== "boolean" || !("params" in candidate)) {
33
- throw new Error("Worker payload is missing required fields.");
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;
34
33
  }
35
- return {
36
- integrationPath: candidate.integrationPath,
37
- exportName: candidate.exportName,
38
- session: candidate.session,
39
- headless: candidate.headless,
40
- debug: candidate.debug,
41
- params: candidate.params
42
- };
43
34
  }
44
35
  async function main() {
45
36
  let request = null;
@@ -49,15 +40,8 @@ async function main() {
49
40
  const workerRequest = request;
50
41
  ensureLibrettoSetup();
51
42
  await withSessionLogger(workerRequest.session, async (logger) => {
52
- await runIntegrationFromFileInWorker(
53
- workerRequest,
54
- logger,
55
- async (details) => {
56
- sendMessage({ type: "paused", details });
57
- }
58
- );
43
+ await runIntegrationFromFileInWorker(workerRequest, logger);
59
44
  });
60
- sendMessage({ type: "completed" });
61
45
  } catch (error) {
62
46
  const message = error instanceof Error ? error.message : String(error);
63
47
  if (request) {
@@ -75,7 +59,6 @@ async function main() {
75
59
  "utf8"
76
60
  );
77
61
  }
78
- sendMessage({ type: "failed", message });
79
62
  exitCode = 1;
80
63
  }
81
64
  process.exit(exitCode);
package/dist/index.cjs CHANGED
@@ -18,18 +18,16 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var index_exports = {};
20
20
  __export(index_exports, {
21
- DebugPauseSignal: () => import_pause.DebugPauseSignal,
22
21
  LIBRETTO_WORKFLOW_BRAND: () => import_workflow.LIBRETTO_WORKFLOW_BRAND,
23
22
  LibrettoWorkflow: () => import_workflow.LibrettoWorkflow,
24
23
  Logger: () => import_logger.Logger,
25
- RunDebugPauseSignal: () => import_api.DebugPauseSignal,
26
24
  SESSION_STATE_VERSION: () => import_state.SESSION_STATE_VERSION,
27
25
  SessionStateFileSchema: () => import_state.SessionStateFileSchema,
28
26
  SessionStatusSchema: () => import_state.SessionStatusSchema,
29
27
  attemptWithRecovery: () => import_recovery.attemptWithRecovery,
30
28
  clearHighlights: () => import_highlight.clearHighlights,
31
29
  createFileLogSink: () => import_sinks.createFileLogSink,
32
- debugPause: () => import_pause.debugPause,
30
+ createLLMClientFromModel: () => import_ai_sdk_adapter.createLLMClientFromModel,
33
31
  defaultLogger: () => import_logger.defaultLogger,
34
32
  detectSubmissionError: () => import_errors.detectSubmissionError,
35
33
  downloadAndSave: () => import_download.downloadAndSave,
@@ -44,17 +42,15 @@ __export(index_exports, {
44
42
  instrumentContext: () => import_instrument.instrumentContext,
45
43
  instrumentPage: () => import_instrument.instrumentPage,
46
44
  isDebugMode: () => import_config.isDebugMode,
47
- isDebugPauseSignal: () => import_pause.isDebugPauseSignal,
48
45
  isDryRun: () => import_config.isDryRun,
49
- isRunDebugPauseSignal: () => import_api.isDebugPauseSignal,
50
46
  jsonlConsoleSink: () => import_sinks.jsonlConsoleSink,
51
47
  launchBrowser: () => import_api.launchBrowser,
52
48
  moveGhostCursor: () => import_ghost_cursor.moveGhostCursor,
53
49
  pageRequest: () => import_network.pageRequest,
54
50
  parseSessionStateContent: () => import_state.parseSessionStateContent,
55
51
  parseSessionStateData: () => import_state.parseSessionStateData,
52
+ pause: () => import_pause.pause,
56
53
  prettyConsoleSink: () => import_sinks.prettyConsoleSink,
57
- runDebugPause: () => import_api.debugPause,
58
54
  serializeSessionState: () => import_state.serializeSessionState,
59
55
  shouldPauseBeforeMutation: () => import_config.shouldPauseBeforeMutation,
60
56
  showHighlight: () => import_highlight.showHighlight,
@@ -63,6 +59,7 @@ __export(index_exports, {
63
59
  module.exports = __toCommonJS(index_exports);
64
60
  var import_logger = require("./shared/logger/logger.js");
65
61
  var import_sinks = require("./shared/logger/sinks.js");
62
+ var import_ai_sdk_adapter = require("./shared/llm/ai-sdk-adapter.js");
66
63
  var import_state = require("./shared/state/index.js");
67
64
  var import_agent = require("./runtime/recovery/agent.js");
68
65
  var import_recovery = require("./runtime/recovery/recovery.js");
@@ -79,18 +76,16 @@ var import_api = require("./shared/run/api.js");
79
76
  var import_workflow = require("./shared/workflow/workflow.js");
80
77
  // Annotate the CommonJS export names for ESM import in node:
81
78
  0 && (module.exports = {
82
- DebugPauseSignal,
83
79
  LIBRETTO_WORKFLOW_BRAND,
84
80
  LibrettoWorkflow,
85
81
  Logger,
86
- RunDebugPauseSignal,
87
82
  SESSION_STATE_VERSION,
88
83
  SessionStateFileSchema,
89
84
  SessionStatusSchema,
90
85
  attemptWithRecovery,
91
86
  clearHighlights,
92
87
  createFileLogSink,
93
- debugPause,
88
+ createLLMClientFromModel,
94
89
  defaultLogger,
95
90
  detectSubmissionError,
96
91
  downloadAndSave,
@@ -105,17 +100,15 @@ var import_workflow = require("./shared/workflow/workflow.js");
105
100
  instrumentContext,
106
101
  instrumentPage,
107
102
  isDebugMode,
108
- isDebugPauseSignal,
109
103
  isDryRun,
110
- isRunDebugPauseSignal,
111
104
  jsonlConsoleSink,
112
105
  launchBrowser,
113
106
  moveGhostCursor,
114
107
  pageRequest,
115
108
  parseSessionStateContent,
116
109
  parseSessionStateData,
110
+ pause,
117
111
  prettyConsoleSink,
118
- runDebugPause,
119
112
  serializeSessionState,
120
113
  shouldPauseBeforeMutation,
121
114
  showHighlight,
package/dist/index.d.cts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { LogOptions, Logger, LoggerApi, LoggerSink, MinimalLogger, defaultLogger } from './shared/logger/logger.cjs';
2
2
  export { createFileLogSink, jsonlConsoleSink, prettyConsoleSink } from './shared/logger/sinks.cjs';
3
3
  export { LLMClient, Message, MessageContentPart } from './shared/llm/types.cjs';
4
+ export { createLLMClientFromModel } from './shared/llm/ai-sdk-adapter.cjs';
4
5
  export { SESSION_STATE_VERSION, SessionState, SessionStateFile, SessionStateFileSchema, SessionStatus, SessionStatusSchema, parseSessionStateContent, parseSessionStateData, serializeSessionState } from './shared/state/session-state.cjs';
5
6
  export { executeRecoveryAgent } from './runtime/recovery/agent.cjs';
6
7
  export { attemptWithRecovery } from './runtime/recovery/recovery.cjs';
@@ -8,12 +9,13 @@ export { DetectedSubmissionError, KnownSubmissionError, detectSubmissionError }
8
9
  export { ExtractOptions, extractFromPage } from './runtime/extract/extract.cjs';
9
10
  export { PageRequestOptions, RequestConfig, pageRequest } from './runtime/network/network.cjs';
10
11
  export { DownloadResult, DownloadViaClickOptions, SaveDownloadOptions, downloadAndSave, downloadViaClick } from './runtime/download/download.cjs';
11
- export { DebugPauseContext, DebugPauseDetails, DebugPauseSignal, DebugPauseContext as RunDebugPauseContext, DebugPauseDetails as RunDebugPauseDetails, DebugPauseSignal as RunDebugPauseSignal, debugPause, isDebugPauseSignal, isDebugPauseSignal as isRunDebugPauseSignal, debugPause as runDebugPause } from './shared/debug/pause.cjs';
12
+ export { pause } from './shared/debug/pause.cjs';
12
13
  export { isDebugMode, isDryRun, shouldPauseBeforeMutation } from './shared/config/config.cjs';
13
14
  export { InstrumentationOptions, InstrumentedPage, installInstrumentation, instrumentContext, instrumentPage } from './shared/instrumentation/instrument.cjs';
14
15
  export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, moveGhostCursor } from './shared/visualization/ghost-cursor.cjs';
15
16
  export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.cjs';
16
17
  export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.cjs';
17
- export { LIBRETTO_WORKFLOW_BRAND, LibrettoAuthProfile, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowMetadata, workflow } from './shared/workflow/workflow.cjs';
18
+ export { LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowMetadata, workflow } from './shared/workflow/workflow.cjs';
18
19
  import 'zod';
20
+ import 'ai';
19
21
  import 'playwright';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export { LogOptions, Logger, LoggerApi, LoggerSink, MinimalLogger, defaultLogger } from './shared/logger/logger.js';
2
2
  export { createFileLogSink, jsonlConsoleSink, prettyConsoleSink } from './shared/logger/sinks.js';
3
3
  export { LLMClient, Message, MessageContentPart } from './shared/llm/types.js';
4
+ export { createLLMClientFromModel } from './shared/llm/ai-sdk-adapter.js';
4
5
  export { SESSION_STATE_VERSION, SessionState, SessionStateFile, SessionStateFileSchema, SessionStatus, SessionStatusSchema, parseSessionStateContent, parseSessionStateData, serializeSessionState } from './shared/state/session-state.js';
5
6
  export { executeRecoveryAgent } from './runtime/recovery/agent.js';
6
7
  export { attemptWithRecovery } from './runtime/recovery/recovery.js';
@@ -8,12 +9,13 @@ export { DetectedSubmissionError, KnownSubmissionError, detectSubmissionError }
8
9
  export { ExtractOptions, extractFromPage } from './runtime/extract/extract.js';
9
10
  export { PageRequestOptions, RequestConfig, pageRequest } from './runtime/network/network.js';
10
11
  export { DownloadResult, DownloadViaClickOptions, SaveDownloadOptions, downloadAndSave, downloadViaClick } from './runtime/download/download.js';
11
- export { DebugPauseContext, DebugPauseDetails, DebugPauseSignal, DebugPauseContext as RunDebugPauseContext, DebugPauseDetails as RunDebugPauseDetails, DebugPauseSignal as RunDebugPauseSignal, debugPause, isDebugPauseSignal, isDebugPauseSignal as isRunDebugPauseSignal, debugPause as runDebugPause } from './shared/debug/pause.js';
12
+ export { pause } from './shared/debug/pause.js';
12
13
  export { isDebugMode, isDryRun, shouldPauseBeforeMutation } from './shared/config/config.js';
13
14
  export { InstrumentationOptions, InstrumentedPage, installInstrumentation, instrumentContext, instrumentPage } from './shared/instrumentation/instrument.js';
14
15
  export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, moveGhostCursor } from './shared/visualization/ghost-cursor.js';
15
16
  export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.js';
16
17
  export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.js';
17
- export { LIBRETTO_WORKFLOW_BRAND, LibrettoAuthProfile, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowMetadata, workflow } from './shared/workflow/workflow.js';
18
+ export { LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowMetadata, workflow } from './shared/workflow/workflow.js';
18
19
  import 'zod';
20
+ import 'ai';
19
21
  import 'playwright';