libretto 0.6.32 → 0.6.33

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.
@@ -49,7 +49,8 @@ function createKernelProvider(options = {}) {
49
49
  const enableRecording = options.enableRecording ?? readBooleanEnv("KERNEL_ENABLE_RECORDING", false);
50
50
  const replays = /* @__PURE__ */ new Map();
51
51
  return {
52
- async createSession() {
52
+ async createSession(sessionOptions) {
53
+ const sessionHeadless = sessionOptions?.headless ?? headless;
53
54
  const json = await kernelFetchJson(
54
55
  endpoint,
55
56
  apiKey,
@@ -57,7 +58,7 @@ function createKernelProvider(options = {}) {
57
58
  {
58
59
  method: "POST",
59
60
  body: JSON.stringify({
60
- headless,
61
+ headless: sessionHeadless,
61
62
  stealth,
62
63
  timeout_seconds: timeoutSeconds
63
64
  })
@@ -25,7 +25,8 @@ function createLibrettoCloudProvider() {
25
25
  json: {
26
26
  timeout_seconds: browserSessionTimeoutSeconds,
27
27
  profile_name: options?.authProfileName,
28
- profile_persist: options?.authProfilePersist
28
+ profile_persist: options?.authProfilePersist,
29
+ headless: options?.headless
29
30
  }
30
31
  })
31
32
  });
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
5
5
  import { basename, dirname, join } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
7
  import { resolveHostedApiUrl } from "./auth-fetch.js";
8
+ import { readAuthState } from "./auth-storage.js";
8
9
  const TELEMETRY_FILE_NAME = "telemetry.json";
9
10
  const TELEMETRY_ENDPOINT_PATH = "/v1/telemetry/recordCliEvent";
10
11
  const TELEMETRY_TIMEOUT_MS = 250;
@@ -66,7 +67,7 @@ function writeTelemetryNotice() {
66
67
  if (!process.stderr.isTTY) return;
67
68
  process.stderr.write(
68
69
  [
69
- "Libretto collects anonymous CLI telemetry: install id, timestamp, command event, error status, package version, and build channel only.",
70
+ "Libretto collects CLI telemetry: install id, timestamp, command event, error status, package version, build channel, and signed-in cloud user id only.",
70
71
  "Set LIBRETTO_TELEMETRY_DISABLED=1 or DO_NOT_TRACK=1 to disable it, or set enabled:false in ~/.libretto/telemetry.json."
71
72
  ].join(" ") + "\n"
72
73
  );
@@ -82,15 +83,26 @@ async function recordCliTelemetryEvent(command, error) {
82
83
  if (isTelemetryDisabled()) return;
83
84
  const installId = await readOrCreateInstallId();
84
85
  if (!installId) return;
86
+ const cloudUserId = await readConfiguredCloudUserId();
85
87
  await sendWithTimeout({
86
88
  installId,
87
89
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
88
90
  event: `libretto ${command.path.join(" ")}`,
89
91
  error,
90
92
  packageVersion,
91
- buildChannel
93
+ buildChannel,
94
+ ...cloudUserId ? { cloudUserId } : {}
92
95
  });
93
96
  }
97
+ async function readConfiguredCloudUserId() {
98
+ try {
99
+ const state = await readAuthState();
100
+ const cloudUserId = state?.session?.userId;
101
+ return cloudUserId && cloudUserId.length > 0 ? cloudUserId : null;
102
+ } catch {
103
+ return null;
104
+ }
105
+ }
94
106
  async function sendWithTimeout(payload) {
95
107
  const controller = new AbortController();
96
108
  const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
package/dist/index.d.ts CHANGED
@@ -14,7 +14,7 @@ export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, mov
14
14
  export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.js';
15
15
  export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.js';
16
16
  export { LibrettoAuthenticateOptions, librettoAuthenticate } from './shared/workflow/authenticate.js';
17
- export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowInputError, LibrettoWorkflowOptions, WorkflowInputValidator, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, validateWorkflowInput, workflow } from './shared/workflow/workflow.js';
17
+ export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowDefinition, LibrettoWorkflowHandler, LibrettoWorkflowInputError, LibrettoWorkflowOptions, WorkflowInputValidator, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, validateWorkflowInput, workflow } from './shared/workflow/workflow.js';
18
18
  export { AuthProfileStorageState, captureAuthProfileStorageState, normalizeAuthProfileSite, parseAuthProfileSites } from './shared/workflow/auth-profile-state.js';
19
19
  import 'zod';
20
20
  import 'playwright';
@@ -3,6 +3,12 @@ import { z } from 'zod';
3
3
  import { RecoveryAction } from '../../runtime/recovery/page-fallbacks.js';
4
4
  import 'ai';
5
5
 
6
+ declare const ViewportConfigSchema: z.ZodObject<{
7
+ width: z.ZodNumber;
8
+ height: z.ZodNumber;
9
+ }, z.core.$strip>;
10
+ type ViewportConfig = z.infer<typeof ViewportConfigSchema>;
11
+
6
12
  declare const LIBRETTO_WORKFLOW_BRAND: unique symbol;
7
13
  type LibrettoWorkflowContext = {
8
14
  session: string;
@@ -18,6 +24,9 @@ type LibrettoWorkflowDefinition<InputSchema extends z.ZodType = z.ZodType<unknow
18
24
  output?: OutputSchema;
19
25
  credentials?: readonly string[];
20
26
  authProfile?: LibrettoWorkflowAuthProfile;
27
+ startUrl?: string;
28
+ gpu?: boolean;
29
+ viewport?: ViewportConfig;
21
30
  recoveryAction?: RecoveryAction;
22
31
  };
23
32
  type LibrettoWorkflowOptions<InputSchema extends z.ZodType = z.ZodType<unknown>, OutputSchema extends z.ZodType = z.ZodType<unknown>> = LibrettoWorkflowDefinition<InputSchema, OutputSchema> & {
@@ -41,6 +50,9 @@ declare class LibrettoWorkflow<InputSchema extends z.ZodType = z.ZodType<unknown
41
50
  readonly credentialNames: readonly string[];
42
51
  readonly authProfileName?: string;
43
52
  readonly authProfileRefresh?: boolean;
53
+ readonly startUrl?: string;
54
+ readonly gpu?: boolean;
55
+ readonly viewport?: ViewportConfig;
44
56
  readonly recoveryAction?: RecoveryAction;
45
57
  private readonly handler;
46
58
  constructor(name: string, options: {
@@ -49,6 +61,9 @@ declare class LibrettoWorkflow<InputSchema extends z.ZodType = z.ZodType<unknown
49
61
  credentialNames?: readonly string[];
50
62
  authProfileName?: string;
51
63
  authProfileRefresh?: boolean;
64
+ startUrl?: string;
65
+ gpu?: boolean;
66
+ viewport?: ViewportConfig;
52
67
  recoveryAction?: RecoveryAction;
53
68
  } | undefined, handler: LibrettoWorkflowHandler<z.infer<InputSchema>, z.infer<OutputSchema>>);
54
69
  run(ctx: LibrettoWorkflowContext, input: unknown): Promise<z.infer<OutputSchema>>;
@@ -61,6 +76,9 @@ type ExportedLibrettoWorkflow = {
61
76
  readonly credentialNames: readonly string[];
62
77
  readonly authProfileName?: string;
63
78
  readonly authProfileRefresh?: boolean;
79
+ readonly startUrl?: string;
80
+ readonly gpu?: boolean;
81
+ readonly viewport?: ViewportConfig;
64
82
  readonly recoveryAction?: RecoveryAction;
65
83
  run: (ctx: LibrettoWorkflowContext, input: unknown) => Promise<unknown>;
66
84
  };
@@ -76,6 +76,9 @@ class LibrettoWorkflow {
76
76
  credentialNames;
77
77
  authProfileName;
78
78
  authProfileRefresh;
79
+ startUrl;
80
+ gpu;
81
+ viewport;
79
82
  recoveryAction;
80
83
  handler;
81
84
  constructor(name, options, handler) {
@@ -85,6 +88,9 @@ class LibrettoWorkflow {
85
88
  this.credentialNames = options?.credentialNames ?? [];
86
89
  this.authProfileName = options?.authProfileName;
87
90
  this.authProfileRefresh = options?.authProfileRefresh;
91
+ this.startUrl = options?.startUrl;
92
+ this.gpu = options?.gpu;
93
+ this.viewport = options?.viewport;
88
94
  this.recoveryAction = options?.recoveryAction;
89
95
  this.handler = handler;
90
96
  }
@@ -159,6 +165,9 @@ function getWorkflowConstructorOptions(options) {
159
165
  credentialNames: normalizeCredentialNames(options.credentials),
160
166
  authProfileName: authProfile?.name,
161
167
  authProfileRefresh: authProfile?.refresh,
168
+ startUrl: options.startUrl,
169
+ gpu: options.gpu,
170
+ viewport: options.viewport,
162
171
  recoveryAction: options.recoveryAction
163
172
  };
164
173
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libretto",
3
- "version": "0.6.32",
3
+ "version": "0.6.33",
4
4
  "description": "AI-powered browser automation library and CLI built on Playwright",
5
5
  "license": "MIT",
6
6
  "homepage": "https://libretto.sh",
@@ -4,7 +4,7 @@ description: "Browser automation CLI for building, maintaining, and running brow
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.32"
7
+ version: "0.6.33"
8
8
  ---
9
9
 
10
10
  ## How Libretto Works
@@ -44,6 +44,18 @@ Prefer to enter sites at a user-facing URL (homepage, login, etc.) on the first
44
44
 
45
45
  - Use `npx libretto experiments` to list internal feature flags and `npx libretto experiments describe <name>` for usage notes when an experiment is enabled.
46
46
 
47
+ ## Run Modes
48
+
49
+ There are three ways to run workflows:
50
+
51
+ - Local browser run: `npx libretto run ./workflow.ts` runs workflow code and local Chromium on the current machine. This is easy to watch and private, but most likely to hit CAPTCHAs or anti-bot checks.
52
+ - Hosted browser run: `npx libretto run ./workflow.ts --provider libretto-cloud` runs workflow code locally while the browser runs on provider infrastructure with stealth mechanisms. Use this for anti-bot/CAPTCHA issues, provider-specific behavior, and pre-deploy validation. If the user has not specified a provider, prefer `libretto-cloud` because it includes one free allocated browser-hour and does not require a third-party provider API key.
53
+ - Deployed workflow: Libretto Cloud packages the workflow as an API-backed workflow with the same remote-browser anti-bot mechanisms as hosted provider runs. Deploy only after the workflow passes with the target provider.
54
+
55
+ When editing a deployed workflow, validate changes with `run --provider <deployment-provider>` before redeploying; do not debug by repeatedly deploying and running the deployed job.
56
+
57
+ If the user prefers a provider for all local CLI runs in a workspace or only deploys workflows to that provider, update `.libretto/config.json` with `provider` instead of repeating `--provider`. Read `references/configuration-file-reference.md` first.
58
+
47
59
  ## Working Rules
48
60
 
49
61
  - Announce which session you are using and what page you are on.
@@ -56,7 +68,7 @@ Prefer to enter sites at a user-facing URL (homepage, login, etc.) on the first
56
68
  - Authenticated workflows must implement `librettoAuthenticate` with declared credentials before validation. Use a reusable `*_totp_secret` credential for authenticator-app MFA, not a one-time `otp_code`; text and email verification codes are not supported for fully automated sign-in.
57
69
  - Read `references/website-authentication.md` when you need `librettoAuthenticate` examples or auth-profile details.
58
70
  - Validation requires a successful clean `run` on a fresh, unauthenticated session with confirmation of the actual returned output, not just process success. Use the same headed or headless mode that the workflow run is already using.
59
- - After validation, always show the user: (1) the output/results from the validation run, and (2) the same command so they can re-run it themselves. Include any `--params`, `--headed`, or `--headless` flags the workflow needs.
71
+ - After validation, always show the user: (1) the output/results from the validation run, and (2) the same command so they can re-run it themselves. Include any `--params`, `--provider`, `--headed`, or `--headless` flags the workflow needs. Do not add `--auth-profile` to `run`; workflow `authProfile` metadata controls profile use.
60
72
  - Treat exploration sessions as disposable unless the user explicitly wants one kept open.
61
73
  - Close disposable sessions before your final response once exploration, debugging, or validation is complete. Open browsers keep consuming local or hosted resources.
62
74
  - Get explicit user confirmation before mutating actions or replaying network requests that may have side effects.
@@ -74,6 +86,7 @@ Prefer to enter sites at a user-facing URL (homepage, login, etc.) on the first
74
86
 
75
87
  ```bash
76
88
  npx libretto open https://example.com
89
+ npx libretto open https://example.com --provider libretto-cloud --session provider-debug
77
90
  npx libretto open https://example.com --read-only --session readonly-example
78
91
  npx libretto open https://example.com --session debug-example
79
92
  ```
@@ -150,6 +163,7 @@ npx libretto exec --session debug-example --page <page-id> "await page.url()"
150
163
  - Use `run` to verify a workflow file after creating it or editing it. Use the same headed or headless mode for validation that the workflow run is already using. Plain `run` defaults to headed mode.
151
164
  - Workflows define their input shape with a Zod schema (see `references/code-generation-rules.md`). `run` validates `--params` against that schema before calling the handler and prints a clear field-by-field error if the input doesn't match.
152
165
  - Successful runs close the browser by default. Pass `--stay-open-on-success` when you need to inspect the completed state with `pages`, `snapshot`, or `exec`.
166
+ - Use `--provider <name>` when validating behavior in that provider's browser runtime.
153
167
  - Pass `--read-only` if the preserved session should come back locked for follow-up terminal inspection after the workflow run.
154
168
  - If the workflow fails, Libretto keeps the browser open. Inspect the failed state with `snapshot` and `exec` before editing code.
155
169
  - Insert `await pause(session)` statements in the workflow file when you need to stop at specific states for interactive debugging, like breakpoints in the browser flow.
@@ -158,6 +172,7 @@ npx libretto exec --session debug-example --page <page-id> "await page.url()"
158
172
 
159
173
  ```bash
160
174
  npx libretto run ./integration.ts --params '{"status":"open"}'
175
+ npx libretto run ./integration.ts --provider libretto-cloud
161
176
  npx libretto run ./integration.ts --read-only
162
177
  npx libretto run ./integration.ts --stay-open-on-success
163
178
  ```
@@ -2,7 +2,7 @@
2
2
 
3
3
  Use this reference when a workflow needs a logged-in website session. The Working Rules in `../SKILL.md` define the required auth workflow; this file explains how to implement sign-in logic with `librettoAuthenticate`, and how auth profiles save signed-in state for later runs.
4
4
 
5
- Build and verify working sign-in logic first. The sign-in code takes priority; an auth profile is added only after the sign-in logic is verified, never as a substitute for it.
5
+ Build and verify working sign-in logic first. Authenticated workflows must use `librettoAuthenticate`; an auth profile is added only after the sign-in logic is verified, never as a substitute for it.
6
6
 
7
7
  ## Sign-In Logic
8
8
 
@@ -44,7 +44,15 @@ export default workflow("accountWorkflow", {
44
44
 
45
45
  Auth profiles save the signed-in browser state (cookies, localStorage, IndexedDB) so later runs can reuse a logged-in session instead of signing in from scratch. The sign-in logic still takes priority: do not add a profile until the `librettoAuthenticate` sign-in step has been verified from a signed-out browser with no profile present. If you add a profile first, validation passes on the saved session while the untested sign-in logic fails the first time that session expires.
46
46
 
47
- A profile only holds whatever a signed-in session wrote into it, so it does nothing until a run has signed in at least once. With `refresh: true`, a successful run writes updated browser state back to the profile, so a fresh sign-in repairs an expired one. Local runs load `.libretto/profiles/<name>.json`; hosted runs use the provider-native profile with the same name.
47
+ A profile only holds whatever a signed-in session wrote into it, so it does nothing until a run has signed in at least once. With `refresh: true`, a successful run writes updated browser state back to the profile, so a fresh sign-in repairs an expired one.
48
+
49
+ Auth profiles are browser-runtime-specific:
50
+
51
+ - Local runs load `.libretto/profiles/<name>.json`.
52
+ - `libretto-cloud` and providers that explicitly support auth profiles use provider-backed profile state; a local profile file is not available to provider browsers.
53
+ - Provider-backed profiles are created or refreshed by workflow-declared `authProfile` metadata. For manual login on a remote provider, run the hosted workflow with a pause/wait, ask the human to sign in through the live URL, use the observed login flow to implement `librettoAuthenticate`, then let the workflow finish so the provider can persist the profile.
54
+ - A plain `open --provider` session does not have workflow auth profile metadata. `libretto save` writes a local profile from an open session; it does not persist provider-backed workflow auth profile state.
55
+ - Revalidate login when switching providers, even if the profile name is the same.
48
56
 
49
57
  Add the profile to the workflow you already verified:
50
58
 
@@ -60,9 +68,15 @@ export default workflow("accountWorkflow", {
60
68
  ## Commands
61
69
 
62
70
  ```bash
71
+ # Open the site in headed mode and ask the user to log in manually.
72
+ npx libretto open https://app.example.com --headed --session login
73
+
63
74
  # Save the current signed-in session as a named, site-scoped profile.
64
75
  npx libretto save example-app --session login --sites app.example.com,auth.example.com
65
76
 
77
+ # You can now reopen the site locally with that profile.
78
+ npx libretto open https://app.example.com --auth-profile example-app
79
+
66
80
  # List or delete hosted auth profile names.
67
81
  npx libretto cloud profiles list
68
82
  npx libretto cloud profiles delete example-app
@@ -71,3 +85,5 @@ npx libretto cloud profiles delete example-app
71
85
  `save` captures cookies, localStorage, and IndexedDB only for the comma-separated `--sites` list.
72
86
 
73
87
  To reuse an existing signed-in Chrome profile instead of signing in, use `npx libretto import-chrome-profiles`. Get the user's consent first, since attaching can close or relaunch their Chrome window.
88
+
89
+ When the user wants to deploy an authenticated workflow, trace the login flow before writing the workflow: open the site with the target provider, inspect behavior while the human signs in, implement `librettoAuthenticate`, then validate the workflow with the auth profile in the target browser runtime.
@@ -4,7 +4,7 @@ description: "Read-only Libretto workflow for diagnosing live browser state with
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.32"
7
+ version: "0.6.33"
8
8
  ---
9
9
 
10
10
  ## How Libretto Read-Only Works