libretto 0.6.31 → 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.
- package/README.md +1 -1
- package/README.template.md +1 -1
- package/dist/cli/commands/auth.js +119 -268
- package/dist/cli/commands/browser.js +1 -0
- package/dist/cli/commands/cloud-credentials.js +5 -17
- package/dist/cli/commands/cloud-jobs.js +125 -0
- package/dist/cli/commands/cloud-schedules.js +128 -0
- package/dist/cli/commands/cloud-settings.js +75 -0
- package/dist/cli/commands/cloud-sharing.js +13 -27
- package/dist/cli/commands/deploy.js +7 -16
- package/dist/cli/commands/execution.js +3 -2
- package/dist/cli/commands/profiles.js +8 -21
- package/dist/cli/commands/shared.js +17 -0
- package/dist/cli/core/browser.js +2 -1
- package/dist/cli/core/daemon/daemon.js +2 -1
- package/dist/cli/core/daemon/ipc.js +23 -16
- package/dist/cli/core/deploy-artifact.js +41 -16
- package/dist/cli/core/providers/kernel.js +3 -2
- package/dist/cli/core/providers/libretto-cloud.js +2 -1
- package/dist/cli/core/telemetry.js +14 -2
- package/dist/cli/router.js +6 -0
- package/dist/index.d.ts +1 -1
- package/dist/shared/workflow/workflow.d.ts +18 -0
- package/dist/shared/workflow/workflow.js +9 -0
- package/package.json +1 -1
- package/skills/libretto/SKILL.md +17 -2
- package/skills/libretto/references/website-authentication.md +18 -2
- package/skills/libretto-readonly/SKILL.md +1 -1
- package/src/cli/commands/auth.ts +169 -382
- package/src/cli/commands/browser.ts +1 -0
- package/src/cli/commands/cloud-credentials.ts +6 -18
- package/src/cli/commands/cloud-jobs.ts +157 -0
- package/src/cli/commands/cloud-schedules.ts +164 -0
- package/src/cli/commands/cloud-settings.ts +101 -0
- package/src/cli/commands/cloud-sharing.ts +20 -28
- package/src/cli/commands/deploy.ts +8 -19
- package/src/cli/commands/execution.ts +2 -1
- package/src/cli/commands/profiles.ts +10 -22
- package/src/cli/commands/shared.ts +29 -0
- package/src/cli/core/browser.ts +2 -0
- package/src/cli/core/daemon/config.ts +1 -0
- package/src/cli/core/daemon/daemon.ts +1 -0
- package/src/cli/core/daemon/ipc.ts +27 -18
- package/src/cli/core/deploy-artifact.ts +63 -14
- package/src/cli/core/providers/kernel.ts +3 -2
- package/src/cli/core/providers/libretto-cloud.ts +1 -0
- package/src/cli/core/providers/types.ts +1 -0
- package/src/cli/core/telemetry.ts +15 -1
- package/src/cli/router.ts +6 -0
- package/src/index.ts +1 -0
- package/src/shared/workflow/workflow.ts +22 -0
|
@@ -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
|
|
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/cli/router.js
CHANGED
|
@@ -2,6 +2,9 @@ import { authCommands } from "./commands/auth.js";
|
|
|
2
2
|
import { billingCommands } from "./commands/billing.js";
|
|
3
3
|
import { browserCommands } from "./commands/browser.js";
|
|
4
4
|
import { cloudCredentialCommands } from "./commands/cloud-credentials.js";
|
|
5
|
+
import { cloudJobCommands } from "./commands/cloud-jobs.js";
|
|
6
|
+
import { cloudScheduleCommands } from "./commands/cloud-schedules.js";
|
|
7
|
+
import { settingsCommands } from "./commands/cloud-settings.js";
|
|
5
8
|
import { codeSharingCommands, shareWorkflowCommand } from "./commands/cloud-sharing.js";
|
|
6
9
|
import { deployCommand } from "./commands/deploy.js";
|
|
7
10
|
import { executionCommands } from "./commands/execution.js";
|
|
@@ -24,7 +27,10 @@ const cliRoutes = {
|
|
|
24
27
|
auth: authCommands,
|
|
25
28
|
billing: billingCommands,
|
|
26
29
|
credentials: cloudCredentialCommands,
|
|
30
|
+
jobs: cloudJobCommands,
|
|
27
31
|
profiles: profileCommands,
|
|
32
|
+
schedules: cloudScheduleCommands,
|
|
33
|
+
settings: settingsCommands,
|
|
28
34
|
share: shareWorkflowCommand,
|
|
29
35
|
sharing: codeSharingCommands
|
|
30
36
|
}
|
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
package/skills/libretto/SKILL.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|