libretto 0.6.12 → 0.6.14
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 +3 -8
- package/README.template.md +3 -8
- package/dist/cli/cli.js +0 -23
- package/dist/cli/commands/auth.js +24 -33
- package/dist/cli/commands/billing.js +3 -5
- package/dist/cli/commands/browser.js +4 -13
- package/dist/cli/commands/deploy.js +54 -45
- package/dist/cli/commands/execution.js +6 -3
- package/dist/cli/commands/experiments.js +1 -1
- package/dist/cli/commands/setup.js +2 -295
- package/dist/cli/commands/shared.js +1 -1
- package/dist/cli/commands/snapshot.js +10 -100
- package/dist/cli/commands/status.js +2 -42
- package/dist/cli/core/auth-fetch.js +11 -6
- package/dist/cli/core/browser.js +13 -8
- package/dist/cli/core/config.js +3 -6
- package/dist/cli/core/daemon/daemon.js +88 -74
- package/dist/cli/core/daemon/exec-repl.js +133 -0
- package/dist/cli/core/daemon/exec.js +6 -21
- package/dist/cli/core/daemon/ipc.js +47 -4
- package/dist/cli/core/daemon/ipc.spec.js +21 -0
- package/dist/cli/core/daemon/snapshot.js +2 -29
- package/dist/cli/core/exec-compiler.js +8 -3
- package/dist/cli/core/experiments.js +1 -28
- package/dist/cli/core/providers/index.js +13 -4
- package/dist/cli/core/providers/libretto-cloud.js +178 -26
- package/dist/cli/index.js +0 -2
- package/dist/cli/router.js +9 -6
- package/dist/shared/instrumentation/instrument.js +4 -4
- package/dist/shared/ipc/socket-transport.d.ts +2 -1
- package/dist/shared/ipc/socket-transport.js +16 -5
- package/dist/shared/ipc/socket-transport.spec.js +5 -0
- package/docs/releasing.md +8 -6
- package/package.json +3 -2
- package/skills/libretto/SKILL.md +49 -47
- package/skills/libretto/references/code-generation-rules.md +6 -0
- package/skills/libretto/references/configuration-file-reference.md +14 -12
- package/skills/libretto/references/pages-and-page-targeting.md +1 -1
- package/skills/libretto/references/site-security-review.md +6 -6
- package/skills/libretto-readonly/SKILL.md +2 -9
- package/src/cli/cli.ts +0 -24
- package/src/cli/commands/auth.ts +24 -33
- package/src/cli/commands/billing.ts +3 -5
- package/src/cli/commands/browser.ts +6 -16
- package/src/cli/commands/deploy.ts +55 -49
- package/src/cli/commands/execution.ts +6 -3
- package/src/cli/commands/experiments.ts +1 -1
- package/src/cli/commands/setup.ts +2 -381
- package/src/cli/commands/shared.ts +1 -1
- package/src/cli/commands/snapshot.ts +9 -137
- package/src/cli/commands/status.ts +2 -50
- package/src/cli/core/auth-fetch.ts +9 -4
- package/src/cli/core/browser.ts +15 -8
- package/src/cli/core/config.ts +3 -6
- package/src/cli/core/daemon/daemon.ts +106 -76
- package/src/cli/core/daemon/exec-repl.ts +189 -0
- package/src/cli/core/daemon/exec.ts +8 -43
- package/src/cli/core/daemon/ipc.spec.ts +27 -0
- package/src/cli/core/daemon/ipc.ts +81 -23
- package/src/cli/core/daemon/snapshot.ts +1 -43
- package/src/cli/core/exec-compiler.ts +8 -3
- package/src/cli/core/experiments.ts +9 -38
- package/src/cli/core/providers/index.ts +17 -4
- package/src/cli/core/providers/libretto-cloud.ts +224 -36
- package/src/cli/core/resolve-model.ts +5 -0
- package/src/cli/core/workflow-runtime.ts +1 -0
- package/src/cli/index.ts +0 -1
- package/src/cli/router.ts +9 -6
- package/src/shared/instrumentation/instrument.ts +4 -4
- package/src/shared/ipc/socket-transport.spec.ts +6 -0
- package/src/shared/ipc/socket-transport.ts +20 -5
- package/dist/cli/commands/ai.js +0 -110
- package/dist/cli/core/ai-model.js +0 -195
- package/dist/cli/core/api-snapshot-analyzer.js +0 -86
- package/dist/cli/core/snapshot-analyzer.js +0 -667
- package/dist/cli/framework/simple-cli.js +0 -880
- package/scripts/summarize-evals.mjs +0 -135
- package/src/cli/commands/ai.ts +0 -144
- package/src/cli/core/ai-model.ts +0 -301
- package/src/cli/core/api-snapshot-analyzer.ts +0 -110
- package/src/cli/core/snapshot-analyzer.ts +0 -856
- package/src/cli/framework/simple-cli.ts +0 -1459
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.14"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## How Libretto Works
|
|
@@ -19,25 +19,29 @@ The npm package includes `src/` (full TypeScript source) and `docs/` for deeper
|
|
|
19
19
|
|
|
20
20
|
Full documentation is published at [libretto.sh](https://libretto.sh). Available pages:
|
|
21
21
|
|
|
22
|
-
- Get started: [
|
|
23
|
-
- Fundamentals: [core concepts](https://libretto.sh/
|
|
24
|
-
- Workflow guides: [one-shot generation](https://libretto.sh/
|
|
25
|
-
- CLI reference: [open and connect](https://libretto.sh/
|
|
26
|
-
- Library API: [workflow](https://libretto.sh/
|
|
27
|
-
- Hosting: [
|
|
22
|
+
- Get started: [quickstart](https://libretto.sh/docs/get-started/quickstart), [first workflow](https://libretto.sh/docs/get-started/first-workflow), [deploying](https://libretto.sh/docs/get-started/deploying)
|
|
23
|
+
- Fundamentals: [core concepts](https://libretto.sh/docs/understand-libretto/core-concepts), [how workflow generation works](https://libretto.sh/docs/understand-libretto/how-workflow-generation-works), [automation and bot detection](https://libretto.sh/docs/understand-libretto/automation-and-bot-detection), [website authentication](https://libretto.sh/docs/understand-libretto/website-authentication)
|
|
24
|
+
- Workflow guides: [one-shot generation](https://libretto.sh/docs/guides/one-shot-workflow-generation), [interactive building](https://libretto.sh/docs/guides/interactive-workflow-building), [debugging workflows](https://libretto.sh/docs/guides/debugging-workflows), [convert to network requests](https://libretto.sh/docs/guides/convert-to-network-requests)
|
|
25
|
+
- CLI reference: [open and connect](https://libretto.sh/docs/reference/cli/open-and-connect), [sessions](https://libretto.sh/docs/reference/cli/sessions), [profiles](https://libretto.sh/docs/reference/cli/profiles), [snapshot](https://libretto.sh/docs/reference/cli/snapshot), [exec](https://libretto.sh/docs/reference/cli/exec), [run and resume](https://libretto.sh/docs/reference/cli/run-and-resume), [session logs](https://libretto.sh/docs/reference/cli/session-logs), [pages](https://libretto.sh/docs/reference/cli/pages)
|
|
26
|
+
- Library API: [workflow](https://libretto.sh/docs/reference/runtime/workflow), [AI extraction](https://libretto.sh/docs/reference/runtime/ai-extraction), [network requests](https://libretto.sh/docs/reference/runtime/network-requests), [file downloads](https://libretto.sh/docs/reference/runtime/file-downloads)
|
|
27
|
+
- Libretto Cloud Hosting: [overview](https://libretto.sh/docs/libretto-cloud-hosting/overview), [authentication](https://libretto.sh/docs/libretto-cloud-hosting/authentication), [deployments](https://libretto.sh/docs/libretto-cloud-hosting/deployments)
|
|
28
|
+
- Alternative providers: [overview](https://libretto.sh/docs/alternative-providers/overview), [Kernel](https://libretto.sh/docs/alternative-providers/kernel), [Browserbase](https://libretto.sh/docs/alternative-providers/browserbase), [GCP](https://libretto.sh/docs/alternative-providers/gcp), [AWS](https://libretto.sh/docs/alternative-providers/aws)
|
|
28
29
|
|
|
29
30
|
## Default Integration Approach
|
|
30
31
|
|
|
31
|
-
-
|
|
32
|
-
-
|
|
33
|
-
-
|
|
32
|
+
- Use Playwright for navigation and other non-fetch browser behavior, including document and asset loads.
|
|
33
|
+
- Prefer browser-context `fetch()` for data extraction and form submission when the target is a real site fetch/XHR endpoint and `references/site-security-review.md` says the path is safe and workable.
|
|
34
|
+
- Use passive interception when the UI already triggers useful fetch/XHR requests or active fetch is risky.
|
|
35
|
+
- Fall back to Playwright UI automation when fetch is ruled out, the request path is not workable, or the user explicitly asks for Playwright/UI automation.
|
|
34
36
|
|
|
35
37
|
## Setup
|
|
36
38
|
|
|
37
|
-
- Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
- Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium and syncs skills.
|
|
40
|
+
- Use `npx libretto status` to inspect open sessions without triggering setup.
|
|
41
|
+
|
|
42
|
+
## Experiments
|
|
43
|
+
|
|
44
|
+
- Use `npx libretto experiments` to list internal feature flags and `npx libretto experiments describe <name>` for usage notes when an experiment is enabled.
|
|
41
45
|
|
|
42
46
|
## Working Rules
|
|
43
47
|
|
|
@@ -46,8 +50,8 @@ Full documentation is published at [libretto.sh](https://libretto.sh). Available
|
|
|
46
50
|
- Do not treat visibility as interactivity. If an element will not act, inspect blockers before retrying.
|
|
47
51
|
- Defer repo/code review until you begin generating code, unless the user explicitly asks for it earlier.
|
|
48
52
|
- Read and follow guidelines in `references/code-generation-rules.md` before generating or editing production workflow code.
|
|
49
|
-
- Validation requires a successful clean `run
|
|
50
|
-
- After validation, always show the user: (1) the output/results from the
|
|
53
|
+
- Validation requires a successful clean `run` 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.
|
|
54
|
+
- 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`, `--headless`, or `--auth-profile` flags the workflow needs.
|
|
51
55
|
- Treat exploration sessions as disposable unless the user explicitly wants one kept open.
|
|
52
56
|
- Get explicit user confirmation before mutating actions or replaying network requests that may have side effects.
|
|
53
57
|
- Never run multiple `exec` commands at the same time.
|
|
@@ -95,20 +99,15 @@ npx libretto session-mode --session my-session
|
|
|
95
99
|
### `snapshot`
|
|
96
100
|
|
|
97
101
|
- Use `snapshot` as the primary page observation tool.
|
|
98
|
-
-
|
|
99
|
-
-
|
|
102
|
+
- Run `snapshot` without `--objective` or `--context`; the command prints a screenshot path and compact accessibility tree for the current page.
|
|
103
|
+
- Run `snapshot <ref>` to inspect a subtree from the latest full snapshot. Use ref forms printed in the tree, such as `l16`; numeric-suffix aliases such as `e16` also match `l16`.
|
|
104
|
+
- Run an unscoped snapshot before using refs. Subtree snapshots capture a fresh screenshot but reuse the latest cached tree.
|
|
100
105
|
- Use it before guessing at selectors, after workflow failures, and whenever the visible page state is unclear.
|
|
101
|
-
- When analysis is involved, expect it to take time. Use a timeout of at least 2 minutes for shell-wrapped calls.
|
|
102
106
|
|
|
103
107
|
```bash
|
|
104
|
-
npx libretto snapshot
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
npx libretto snapshot \
|
|
108
|
-
--session debug-example \
|
|
109
|
-
--page <page-id> \
|
|
110
|
-
--objective "Explain why the table is empty" \
|
|
111
|
-
--context "I opened the referrals page, applied filters, and expected rows to appear."
|
|
108
|
+
npx libretto snapshot --session debug-example
|
|
109
|
+
npx libretto snapshot <ref> --session debug-example
|
|
110
|
+
npx libretto snapshot --session debug-example --page <page-id>
|
|
112
111
|
```
|
|
113
112
|
|
|
114
113
|
### `exec`
|
|
@@ -116,16 +115,18 @@ npx libretto snapshot \
|
|
|
116
115
|
- Use `exec` for focused inspection and short-lived interaction experiments.
|
|
117
116
|
- Use `exec` to validate selectors, inspect data, or prototype a step before you encode it in the workflow file.
|
|
118
117
|
- Use `exec -` to run multi-line scripts from stdin, especially when the code is too long or complex for a command line argument.
|
|
119
|
-
-
|
|
118
|
+
- The `exec` REPL is persistent for each browser session. Define helper functions once and reuse them in later `exec` calls.
|
|
119
|
+
- Available globals: `page`, `frame`, `context`, `browser`, `fetch`, `Buffer`.
|
|
120
120
|
- Let failures throw. Do not hide `exec` failures with `try/catch` or `.catch()`.
|
|
121
121
|
- Do not run multiple `exec` commands in parallel.
|
|
122
122
|
- Do not use `exec` in read-only diagnosis flows. Use `readonly-exec` from the `libretto-readonly` skill for those sessions.
|
|
123
|
+
- After successful mutations, `exec` prints page-change diffs from compact snapshots.
|
|
123
124
|
|
|
124
125
|
```bash
|
|
125
|
-
npx libretto exec "
|
|
126
|
-
npx libretto exec "return await page.locator('button').count()"
|
|
126
|
+
npx libretto exec "await page.url()"
|
|
127
127
|
npx libretto exec "await page.locator('button:has-text(\"Continue\")').click()"
|
|
128
|
-
echo "return await page.
|
|
128
|
+
echo "async function textOf(selector) { return await page.locator(selector).textContent(); }" | npx libretto exec - --session debug-example
|
|
129
|
+
npx libretto exec --session debug-example "await textOf('h1')"
|
|
129
130
|
```
|
|
130
131
|
|
|
131
132
|
### `pages`
|
|
@@ -135,13 +136,13 @@ echo "return await page.url()" | npx libretto exec - --session debug-example
|
|
|
135
136
|
|
|
136
137
|
```bash
|
|
137
138
|
npx libretto pages --session debug-example
|
|
138
|
-
npx libretto exec --session debug-example --page <page-id> "
|
|
139
|
+
npx libretto exec --session debug-example --page <page-id> "await page.url()"
|
|
139
140
|
```
|
|
140
141
|
|
|
141
142
|
### `run`
|
|
142
143
|
|
|
143
|
-
- Use `run` to verify a workflow file after creating it or editing it
|
|
144
|
-
- Plain `run` defaults to headed mode.
|
|
144
|
+
- 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.
|
|
145
|
+
- Plain `run` defaults to headed mode. Do not use `--headless` unless the user asks for headless mode or the existing workflow run already uses it.
|
|
145
146
|
- 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`.
|
|
146
147
|
- Pass `--read-only` if the preserved session should come back locked for follow-up terminal inspection after the workflow run.
|
|
147
148
|
- If the workflow fails, Libretto keeps the browser open. Inspect the failed state with `snapshot` and `exec` before editing code.
|
|
@@ -150,9 +151,9 @@ npx libretto exec --session debug-example --page <page-id> "return await page.ur
|
|
|
150
151
|
- Re-run the same workflow after each fix to verify the browser behavior end to end.
|
|
151
152
|
|
|
152
153
|
```bash
|
|
153
|
-
npx libretto run ./integration.ts --
|
|
154
|
-
npx libretto run ./integration.ts --
|
|
155
|
-
npx libretto run ./integration.ts --
|
|
154
|
+
npx libretto run ./integration.ts --params '{"status":"open"}'
|
|
155
|
+
npx libretto run ./integration.ts --read-only
|
|
156
|
+
npx libretto run ./integration.ts --stay-open-on-success
|
|
156
157
|
npx libretto run ./integration.ts --auth-profile app.example.com
|
|
157
158
|
```
|
|
158
159
|
|
|
@@ -227,15 +228,15 @@ Key fields: `ts` (ISO timestamp), `method` (HTTP method, e.g. `GET`, `POST`), `u
|
|
|
227
228
|
Assistant: I'll inspect the real site first if needed, but before I finish I'll create `target-workflow.ts` so the task produces reusable automation code.
|
|
228
229
|
Assistant: [Runs `npx libretto open https://target.example.com --headed`]
|
|
229
230
|
Assistant: [Reads `references/site-security-review.md` before choosing between passive network inspection, direct browser fetch calls, and Playwright-first automation]
|
|
230
|
-
Assistant: [Runs `npx libretto snapshot --
|
|
231
|
+
Assistant: [Runs `npx libretto snapshot --session <session>`]
|
|
231
232
|
Assistant: [Uses `snapshot` and `exec` as needed to understand the site and decide the implementation path]
|
|
232
233
|
Assistant: [Reads `references/code-generation-rules.md` before writing production workflow code]
|
|
233
234
|
Assistant: I found the working path. I'll now create the workflow file and verify it.
|
|
234
235
|
Assistant: [Creates or edits `target-workflow.ts` following `references/code-generation-rules.md`]
|
|
235
|
-
Assistant: [Runs `npx libretto run ./target-workflow.ts --
|
|
236
|
+
Assistant: [Runs `npx libretto run ./target-workflow.ts --params '{"status":"open"}'` to validate]
|
|
236
237
|
Assistant: Validation passed. Here are the results:
|
|
237
|
-
[Shows the output/results from the
|
|
238
|
-
To
|
|
238
|
+
[Shows the output/results from the validation run]
|
|
239
|
+
To run it again, use: npx libretto run ./target-workflow.ts --params '{"status":"open"}'
|
|
239
240
|
</example>
|
|
240
241
|
```
|
|
241
242
|
|
|
@@ -245,25 +246,26 @@ To watch it yourself in a browser, run: npx libretto run ./target-workflow.ts --
|
|
|
245
246
|
<example>
|
|
246
247
|
[Context: The user has an existing Libretto workflow that is failing]
|
|
247
248
|
Assistant: I'll reproduce the failure first so we can inspect the exact browser state it leaves behind.
|
|
248
|
-
Assistant: [Runs `npx libretto run ./integration.ts --session debug-flow
|
|
249
|
+
Assistant: [Runs `npx libretto run ./integration.ts --session debug-flow`]
|
|
249
250
|
Assistant: The workflow failed and Libretto kept the browser open. I'll inspect the page state before changing code.
|
|
250
|
-
Assistant: [Runs `npx libretto snapshot --session debug-flow
|
|
251
|
+
Assistant: [Runs `npx libretto snapshot --session debug-flow`]
|
|
251
252
|
Assistant: [Runs `npx libretto exec --session debug-flow "...focused inspection or prototype..."`]
|
|
252
253
|
Assistant: [Reads `references/code-generation-rules.md` before patching the workflow file]
|
|
253
254
|
Assistant: I found the issue. I'll patch the workflow code and verify.
|
|
254
255
|
Assistant: [Edits `integration.ts` following `references/code-generation-rules.md`]
|
|
255
|
-
Assistant: [Runs `npx libretto run ./integration.ts
|
|
256
|
+
Assistant: [Runs `npx libretto run ./integration.ts` to validate the fix]
|
|
256
257
|
Assistant: Fix verified. Here are the results:
|
|
257
|
-
[Shows the output/results from the
|
|
258
|
-
To
|
|
258
|
+
[Shows the output/results from the validation run]
|
|
259
|
+
To run it again, use: npx libretto run ./integration.ts
|
|
259
260
|
</example>
|
|
260
261
|
```
|
|
261
262
|
|
|
262
263
|
## References
|
|
263
264
|
|
|
264
|
-
- Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for
|
|
265
|
+
- Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for viewport or session defaults.
|
|
265
266
|
- Read `references/site-security-review.md` before reviewing the site's security posture and deciding whether to lead with network requests, passive interception, or Playwright DOM automation on a new site.
|
|
266
267
|
- Read `references/code-generation-rules.md` before writing or editing production workflow files.
|
|
267
268
|
- Read `references/auth-profiles.md` when auth-profile behavior is relevant.
|
|
268
269
|
- Read `references/pages-and-page-targeting.md` when a session has multiple open pages or you need `--page`.
|
|
269
270
|
- Read `references/action-logs.md` for full action log field descriptions and user-vs-agent event semantics.
|
|
271
|
+
- If the workflow code is deployed to the Libretto Cloud platform and you need to reference its API docs, fetch [https://libretto.sh/docs/llms.txt](https://libretto.sh/docs/llms.txt) and follow the relevant page links.
|
|
@@ -117,6 +117,12 @@ Do not rely on broad DOM querying inside `page.evaluate()` for production flows
|
|
|
117
117
|
|
|
118
118
|
## Network Request Methods
|
|
119
119
|
|
|
120
|
+
Network request methods are for active fetch/XHR endpoints the site already uses. Prefer them for data extraction or form submissions when the security review shows the path is safe and workable.
|
|
121
|
+
|
|
122
|
+
Before codifying a network request, confirm that the browser primitive matches how the site normally makes that request. Use `page.goto()` or link clicks for document navigation. Use `page.evaluate(fetch)` only for endpoints the site calls with fetch/XHR. Let the DOM load scripts, images, stylesheets, and iframes naturally, or create the corresponding DOM element if you truly need that request type.
|
|
123
|
+
|
|
124
|
+
Do not use `fetch()` to avoid UI navigation for page HTML or asset URLs. The request still comes from the browser, but the browser marks it as fetch/XHR with different request-context headers than a navigation, script, image, stylesheet, or iframe load. Do not try to fix that by copying headers, because the browser controls the request context. Prefer passive network interception when the site's own UI already triggers the useful request.
|
|
125
|
+
|
|
120
126
|
When codifying network-based data extraction or form submissions, wrap `page.evaluate(() => fetch(...))` calls in typed methods on a shared API client class:
|
|
121
127
|
|
|
122
128
|
```typescript
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
# Configuration File Reference
|
|
2
2
|
|
|
3
|
-
Use this reference when you need to inspect or change
|
|
3
|
+
Use this reference when you need to inspect or change workspace configuration for default browser behavior.
|
|
4
4
|
|
|
5
5
|
## When to Use This
|
|
6
6
|
|
|
7
|
-
- You want to confirm which AI model `snapshot` will use.
|
|
8
7
|
- You want to understand where Libretto stores workspace-level settings.
|
|
9
8
|
- You want a persistent default viewport for `open` or `run`.
|
|
9
|
+
- You want a persistent default browser provider, such as Kernel or Browserbase.
|
|
10
10
|
|
|
11
11
|
## File Location
|
|
12
12
|
|
|
13
13
|
Libretto reads workspace config from `.libretto/config.json`.
|
|
14
14
|
|
|
15
|
-
- The file is created by `npx libretto setup` during first-time onboarding
|
|
16
|
-
-
|
|
17
|
-
- Use `npx libretto status` to inspect the current AI configuration and open sessions without changing anything.
|
|
15
|
+
- The file is created by `npx libretto setup` during first-time onboarding.
|
|
16
|
+
- Use `npx libretto status` to inspect open sessions without changing anything.
|
|
18
17
|
- For first-time setup instructions, follow the main `SKILL.md` flow instead of expanding this reference.
|
|
19
18
|
|
|
20
19
|
## Supported Settings
|
|
21
20
|
|
|
22
|
-
- `
|
|
21
|
+
- `provider` is an optional top-level setting used by `open` and `run` when you do not pass `--provider` and do not set `LIBRETTO_PROVIDER`. Must be `"local"`, `"kernel"`, `"browserbase"`, or `"libretto-cloud"`.
|
|
22
|
+
- Provider precedence is: CLI `--provider`, then `LIBRETTO_PROVIDER`, then `.libretto/config.json`, then `"local"`.
|
|
23
|
+
- Provider credentials belong in the repo root `.env` file, which Libretto loads automatically before running CLI commands.
|
|
23
24
|
- `viewport` is an optional top-level setting used by `open` and `run` when you do not pass `--viewport`.
|
|
24
25
|
- Viewport precedence is: CLI `--viewport`, then `.libretto/config.json`, then the default `1366x768`.
|
|
25
26
|
- `sessionMode` sets the default session access mode for new sessions created by `open`, `connect`, and `run`. Must be `"read-only"` or `"write-access"`. When omitted, defaults to `"write-access"`. Pass `--read-only` or `--write-access` to `open`, `connect`, or `run` to override when creating a session.
|
|
@@ -29,7 +30,7 @@ Example:
|
|
|
29
30
|
```json
|
|
30
31
|
{
|
|
31
32
|
"version": 1,
|
|
32
|
-
"
|
|
33
|
+
"provider": "kernel",
|
|
33
34
|
"viewport": {
|
|
34
35
|
"width": 1280,
|
|
35
36
|
"height": 800
|
|
@@ -41,15 +42,16 @@ Example:
|
|
|
41
42
|
## Common Commands
|
|
42
43
|
|
|
43
44
|
```bash
|
|
44
|
-
npx libretto setup # first-time onboarding
|
|
45
|
-
npx libretto status # inspect
|
|
46
|
-
npx libretto
|
|
45
|
+
npx libretto setup # first-time onboarding
|
|
46
|
+
npx libretto status # inspect open sessions
|
|
47
|
+
npx libretto open https://example.com --provider kernel
|
|
48
|
+
npx libretto run ./integration.ts --provider browserbase
|
|
47
49
|
npx libretto open https://example.com --viewport 1440x900
|
|
48
50
|
npx libretto run ./integration.ts --viewport 1440x900
|
|
49
51
|
```
|
|
50
52
|
|
|
51
53
|
## Notes
|
|
52
54
|
|
|
55
|
+
- If you want a persistent default provider for the workspace, add `provider` to `.libretto/config.json` instead of repeating `--provider` on every command.
|
|
53
56
|
- If you want a persistent default viewport for the workspace, add `viewport` to `.libretto/config.json` instead of repeating `--viewport` on every command.
|
|
54
|
-
-
|
|
55
|
-
- Run `npx libretto status` at any time to check which model is active and whether credentials are present.
|
|
57
|
+
- Run `npx libretto status` at any time to check open sessions.
|
|
@@ -19,7 +19,7 @@ Use this reference when a Libretto session has multiple open pages and you need
|
|
|
19
19
|
```bash
|
|
20
20
|
npx libretto pages --session debug-flow
|
|
21
21
|
npx libretto exec --session debug-flow --page <page-id> "return await page.url()"
|
|
22
|
-
npx libretto snapshot --session debug-flow --page <page-id>
|
|
22
|
+
npx libretto snapshot --session debug-flow --page <page-id>
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Notes
|
|
@@ -60,10 +60,11 @@ Use the review above to decide what is safe to prioritize. Every integration use
|
|
|
60
60
|
|
|
61
61
|
### Strategy A: Prioritize `page.evaluate(fetch(...))`
|
|
62
62
|
|
|
63
|
-
Make fetch calls directly from within the browser's JavaScript context.
|
|
63
|
+
Make fetch calls directly from within the browser's JavaScript context. Use this only for endpoints the site already calls with fetch/XHR, not for page navigation or asset loads.
|
|
64
64
|
|
|
65
65
|
When to prioritize this:
|
|
66
66
|
|
|
67
|
+
- The target endpoint is normally called by the site with fetch/XHR
|
|
67
68
|
- No enterprise bot protection is detected
|
|
68
69
|
- `fetch` is not monkey-patched
|
|
69
70
|
- The API responses are parseable and useful
|
|
@@ -71,7 +72,7 @@ When to prioritize this:
|
|
|
71
72
|
|
|
72
73
|
Why: maximum control and efficiency. You call exactly the endpoints you want with the parameters you want, skip UI rendering, and get structured JSON back. On sites without aggressive detection, this is the fastest and cleanest approach.
|
|
73
74
|
|
|
74
|
-
Risk:
|
|
75
|
+
Risk: fetch is the wrong primitive for page HTML and asset URLs; use Playwright navigation or DOM-driven loads for those. Sites can also monitor fetch call stacks and flag calls that do not originate from the site's bundled code.
|
|
75
76
|
|
|
76
77
|
You will still use Playwright for initial navigation, login/auth flows, cookie consent, and any UI interactions needed to establish session state before making fetch calls.
|
|
77
78
|
|
|
@@ -111,10 +112,9 @@ Trade-off: it is slower, more fragile against DOM changes, and you only get data
|
|
|
111
112
|
|
|
112
113
|
| Site Profile | Primary Strategy | Supplement With |
|
|
113
114
|
| --- | --- | --- |
|
|
114
|
-
| No bot protection, fetch not patched | A (`page.evaluate(fetch)`) | Playwright for navigation/auth |
|
|
115
|
-
| No bot protection, fetch is patched | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
|
|
116
|
-
| Bot protection detected
|
|
117
|
-
| Bot protection detected, fetch is patched | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
|
|
115
|
+
| No bot protection, fetch/XHR endpoint, fetch not patched | A (`page.evaluate(fetch)`) | Playwright for navigation/auth |
|
|
116
|
+
| No bot protection, fetch is patched or endpoint is not fetch/XHR | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
|
|
117
|
+
| Bot protection detected | B (`page.on('response', ...)`) | Playwright for navigation; cautious use of `page.evaluate(fetch)` only if needed |
|
|
118
118
|
| Server-rendered content (no API calls) | C (DOM extraction) | Playwright for all interaction |
|
|
119
119
|
|
|
120
120
|
## Output: Site Assessment Summary
|
|
@@ -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.
|
|
7
|
+
version: "0.6.14"
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
## How Libretto Read-Only Works
|
|
@@ -49,14 +49,7 @@ npx libretto pages --session failed-job-debug
|
|
|
49
49
|
### `snapshot`
|
|
50
50
|
|
|
51
51
|
- Use `snapshot` as the first high-level observation tool.
|
|
52
|
-
-
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
npx libretto snapshot \
|
|
56
|
-
--session failed-job-debug \
|
|
57
|
-
--objective "Identify the visible failure state and likely blocking UI condition" \
|
|
58
|
-
--context "The workflow already failed and the preserved browser must remain read-only."
|
|
59
|
-
```
|
|
52
|
+
- Run `snapshot <ref>` to inspect a subtree from the latest full snapshot.
|
|
60
53
|
|
|
61
54
|
### `readonly-exec`
|
|
62
55
|
|
package/src/cli/cli.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import { resolveAiSetupStatus } from "./core/ai-model.js";
|
|
2
1
|
import { ensureLibrettoSetup } from "./core/context.js";
|
|
3
|
-
import { librettoCommand } from "../shared/package-manager.js";
|
|
4
2
|
import { createCLIApp } from "./router.js";
|
|
5
3
|
import { warnIfInstalledSkillOutOfDate } from "./core/skill-version.js";
|
|
6
4
|
import { loadEnv } from "../shared/env/load-env.js";
|
|
@@ -17,28 +15,6 @@ Docs (agent-friendly): https://libretto.sh/docs
|
|
|
17
15
|
|
|
18
16
|
function printSetupAudit(): void {
|
|
19
17
|
warnIfInstalledSkillOutOfDate();
|
|
20
|
-
|
|
21
|
-
const status = resolveAiSetupStatus();
|
|
22
|
-
switch (status.kind) {
|
|
23
|
-
case "ready":
|
|
24
|
-
console.log(`✓ Snapshot model: ${status.model}`);
|
|
25
|
-
break;
|
|
26
|
-
case "configured-missing-credentials":
|
|
27
|
-
console.log(
|
|
28
|
-
`✗ ${status.provider} configured (model: ${status.model}), but credentials are missing. Run \`${librettoCommand("setup")}\` to repair.`,
|
|
29
|
-
);
|
|
30
|
-
break;
|
|
31
|
-
case "invalid-config":
|
|
32
|
-
console.log(
|
|
33
|
-
`✗ AI config is invalid. Run \`${librettoCommand("setup")}\` to reconfigure.`,
|
|
34
|
-
);
|
|
35
|
-
break;
|
|
36
|
-
case "unconfigured":
|
|
37
|
-
console.log(
|
|
38
|
-
`✗ No AI model configured. Run \`${librettoCommand("setup")}\` or \`${librettoCommand("ai configure")}\` to set up.`,
|
|
39
|
-
);
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
18
|
}
|
|
43
19
|
|
|
44
20
|
function isRootHelpRequest(rawArgs: readonly string[]): boolean {
|
package/src/cli/commands/auth.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Hosted-platform auth commands.
|
|
3
3
|
*
|
|
4
|
-
* libretto
|
|
5
|
-
* libretto
|
|
6
|
-
* libretto
|
|
7
|
-
* libretto
|
|
8
|
-
* libretto
|
|
9
|
-
* libretto
|
|
10
|
-
* libretto
|
|
11
|
-
* libretto
|
|
12
|
-
* libretto
|
|
4
|
+
* libretto cloud auth signup
|
|
5
|
+
* libretto cloud auth login
|
|
6
|
+
* libretto cloud auth logout
|
|
7
|
+
* libretto cloud auth invite <email> [--role member|admin|owner]
|
|
8
|
+
* libretto cloud auth accept-invite <tenantSlug> <invitationId>
|
|
9
|
+
* libretto cloud auth api-key issue [--label <label>]
|
|
10
|
+
* libretto cloud auth api-key list
|
|
11
|
+
* libretto cloud auth api-key revoke <id>
|
|
12
|
+
* libretto cloud auth whoami
|
|
13
13
|
*
|
|
14
14
|
* Credentials live at ~/.libretto/auth.json (mode 0600). The CLI sends either
|
|
15
15
|
* the stored API key or the stored session cookie depending on what's
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { z } from "zod";
|
|
20
|
-
import { SimpleCLI } from "
|
|
20
|
+
import { SimpleCLI } from "affordance";
|
|
21
21
|
import {
|
|
22
22
|
ApiCallError,
|
|
23
23
|
betterAuthCall,
|
|
24
|
-
HOSTED_API_URL,
|
|
25
24
|
NOT_AUTHENTICATED_MESSAGE,
|
|
26
25
|
orpcCall,
|
|
27
26
|
pickCredential,
|
|
28
27
|
resolveApiUrl,
|
|
28
|
+
resolveHostedApiUrl,
|
|
29
29
|
} from "../core/auth-fetch.js";
|
|
30
30
|
import {
|
|
31
31
|
authStatePath,
|
|
@@ -198,11 +198,10 @@ async function issueApiKey(
|
|
|
198
198
|
|
|
199
199
|
export const signupCommand = SimpleCLI.command({
|
|
200
200
|
description: "Create a new hosted-platform account and organization",
|
|
201
|
-
experimental: true,
|
|
202
201
|
})
|
|
203
202
|
.input(SimpleCLI.input({ positionals: [], named: {} }))
|
|
204
203
|
.handle(async () => {
|
|
205
|
-
const apiUrl =
|
|
204
|
+
const apiUrl = resolveHostedApiUrl();
|
|
206
205
|
console.log("Sign up for libretto cloud");
|
|
207
206
|
console.log();
|
|
208
207
|
console.log("Heads up: a libretto user can only belong to one organization.");
|
|
@@ -215,7 +214,7 @@ export const signupCommand = SimpleCLI.command({
|
|
|
215
214
|
const name = await prompt("Your name:");
|
|
216
215
|
if (name.toLowerCase() === "q" || name.length === 0) {
|
|
217
216
|
console.log(
|
|
218
|
-
"OK — ask an existing teammate to run `libretto
|
|
217
|
+
"OK — ask an existing teammate to run `libretto cloud auth invite <your-email>` and then run `libretto cloud auth accept-invite <slug> <invitation-id>` from this machine.",
|
|
219
218
|
);
|
|
220
219
|
return;
|
|
221
220
|
}
|
|
@@ -294,7 +293,7 @@ export const signupCommand = SimpleCLI.command({
|
|
|
294
293
|
console.log(`Session saved to ${authStatePath()}`);
|
|
295
294
|
console.log();
|
|
296
295
|
console.log("To generate an API key, run:");
|
|
297
|
-
console.log(" libretto
|
|
296
|
+
console.log(" libretto cloud auth api-key issue --label <label>");
|
|
298
297
|
console.log("Then add LIBRETTO_API_KEY=<key> to your project's .env file.");
|
|
299
298
|
});
|
|
300
299
|
|
|
@@ -304,11 +303,10 @@ export const signupCommand = SimpleCLI.command({
|
|
|
304
303
|
|
|
305
304
|
export const loginCommand = SimpleCLI.command({
|
|
306
305
|
description: "Sign in to an existing hosted-platform account",
|
|
307
|
-
experimental: true,
|
|
308
306
|
})
|
|
309
307
|
.input(SimpleCLI.input({ positionals: [], named: {} }))
|
|
310
308
|
.handle(async () => {
|
|
311
|
-
const apiUrl =
|
|
309
|
+
const apiUrl = resolveHostedApiUrl();
|
|
312
310
|
|
|
313
311
|
const email = await prompt("Email:");
|
|
314
312
|
const password = await promptPassword("Password:");
|
|
@@ -375,7 +373,6 @@ export const loginCommand = SimpleCLI.command({
|
|
|
375
373
|
|
|
376
374
|
export const logoutCommand = SimpleCLI.command({
|
|
377
375
|
description: "Clear local libretto credentials",
|
|
378
|
-
experimental: true,
|
|
379
376
|
})
|
|
380
377
|
.handle(async () => {
|
|
381
378
|
const state = await readAuthState();
|
|
@@ -400,7 +397,6 @@ export const logoutCommand = SimpleCLI.command({
|
|
|
400
397
|
|
|
401
398
|
export const inviteCommand = SimpleCLI.command({
|
|
402
399
|
description: "Invite a teammate to your active organization",
|
|
403
|
-
experimental: true,
|
|
404
400
|
})
|
|
405
401
|
.input(
|
|
406
402
|
SimpleCLI.input({
|
|
@@ -475,7 +471,7 @@ export const inviteCommand = SimpleCLI.command({
|
|
|
475
471
|
console.log();
|
|
476
472
|
console.log("Tell them to run:");
|
|
477
473
|
console.log(
|
|
478
|
-
` libretto
|
|
474
|
+
` libretto cloud auth accept-invite ${orgSlug} ${data.id}`,
|
|
479
475
|
);
|
|
480
476
|
});
|
|
481
477
|
|
|
@@ -485,7 +481,6 @@ export const inviteCommand = SimpleCLI.command({
|
|
|
485
481
|
|
|
486
482
|
export const acceptInviteCommand = SimpleCLI.command({
|
|
487
483
|
description: "Accept an organization invitation",
|
|
488
|
-
experimental: true,
|
|
489
484
|
})
|
|
490
485
|
.input(
|
|
491
486
|
SimpleCLI.input({
|
|
@@ -514,7 +509,7 @@ export const acceptInviteCommand = SimpleCLI.command({
|
|
|
514
509
|
)
|
|
515
510
|
.handle(async ({ input }) => {
|
|
516
511
|
const stored = await readAuthState();
|
|
517
|
-
const apiUrl =
|
|
512
|
+
const apiUrl = resolveHostedApiUrl();
|
|
518
513
|
const credential = pickCredential(stored);
|
|
519
514
|
const expectedTenantSlug = input.tenantSlug;
|
|
520
515
|
|
|
@@ -535,7 +530,7 @@ export const acceptInviteCommand = SimpleCLI.command({
|
|
|
535
530
|
[
|
|
536
531
|
"You're already a member of an organization.",
|
|
537
532
|
"A libretto user can only belong to one organization at a time.",
|
|
538
|
-
"To accept this invite: log out, delete the existing account, and re-run `auth accept-invite` with a new account (or a fresh email).",
|
|
533
|
+
"To accept this invite: log out, delete the existing account, and re-run `libretto cloud auth accept-invite` with a new account (or a fresh email).",
|
|
539
534
|
].join("\n"),
|
|
540
535
|
);
|
|
541
536
|
}
|
|
@@ -611,7 +606,7 @@ export const acceptInviteCommand = SimpleCLI.command({
|
|
|
611
606
|
console.log();
|
|
612
607
|
console.log("Email verified. You're logged in and a member of the organization.");
|
|
613
608
|
console.log("To generate an API key, run:");
|
|
614
|
-
console.log(" libretto
|
|
609
|
+
console.log(" libretto cloud auth api-key issue --label <label>");
|
|
615
610
|
console.log("Then add LIBRETTO_API_KEY=<key> to your project's .env file.");
|
|
616
611
|
});
|
|
617
612
|
|
|
@@ -621,7 +616,6 @@ export const acceptInviteCommand = SimpleCLI.command({
|
|
|
621
616
|
|
|
622
617
|
export const apiKeyIssueCommand = SimpleCLI.command({
|
|
623
618
|
description: "Issue a new API key for the active organization",
|
|
624
|
-
experimental: true,
|
|
625
619
|
})
|
|
626
620
|
.input(
|
|
627
621
|
SimpleCLI.input({
|
|
@@ -658,7 +652,6 @@ export const apiKeyIssueCommand = SimpleCLI.command({
|
|
|
658
652
|
|
|
659
653
|
export const apiKeyListCommand = SimpleCLI.command({
|
|
660
654
|
description: "List API keys for the active organization",
|
|
661
|
-
experimental: true,
|
|
662
655
|
})
|
|
663
656
|
.handle(async () => {
|
|
664
657
|
const stored = await readAuthState();
|
|
@@ -691,13 +684,12 @@ export const apiKeyListCommand = SimpleCLI.command({
|
|
|
691
684
|
|
|
692
685
|
export const apiKeyRevokeCommand = SimpleCLI.command({
|
|
693
686
|
description: "Revoke an API key by id",
|
|
694
|
-
experimental: true,
|
|
695
687
|
})
|
|
696
688
|
.input(
|
|
697
689
|
SimpleCLI.input({
|
|
698
690
|
positionals: [
|
|
699
691
|
SimpleCLI.positional("id", z.string().min(1), {
|
|
700
|
-
help: "API key id (from `auth api-key list`).",
|
|
692
|
+
help: "API key id (from `libretto cloud auth api-key list`).",
|
|
701
693
|
}),
|
|
702
694
|
],
|
|
703
695
|
named: {},
|
|
@@ -720,7 +712,7 @@ export const apiKeyRevokeCommand = SimpleCLI.command({
|
|
|
720
712
|
|
|
721
713
|
console.log(`API key ${input.id} revoked.`);
|
|
722
714
|
console.log(
|
|
723
|
-
"If this key was in your .env, remove the LIBRETTO_API_KEY value and issue a new one with `auth api-key issue --label <label>`.",
|
|
715
|
+
"If this key was in your .env, remove the LIBRETTO_API_KEY value and issue a new one with `libretto cloud auth api-key issue --label <label>`.",
|
|
724
716
|
);
|
|
725
717
|
});
|
|
726
718
|
|
|
@@ -730,7 +722,6 @@ export const apiKeyRevokeCommand = SimpleCLI.command({
|
|
|
730
722
|
|
|
731
723
|
export const whoamiCommand = SimpleCLI.command({
|
|
732
724
|
description: "Print the active session and credential source",
|
|
733
|
-
experimental: true,
|
|
734
725
|
})
|
|
735
726
|
.handle(async () => {
|
|
736
727
|
const stored = await readAuthState();
|
|
@@ -740,13 +731,13 @@ export const whoamiCommand = SimpleCLI.command({
|
|
|
740
731
|
|
|
741
732
|
if (credential.source === "none") {
|
|
742
733
|
console.log(
|
|
743
|
-
"Not authenticated. Run `libretto
|
|
734
|
+
"Not authenticated. Run `libretto cloud auth signup`, `libretto cloud auth login`, or set LIBRETTO_API_KEY in your env.",
|
|
744
735
|
);
|
|
745
736
|
return;
|
|
746
737
|
}
|
|
747
738
|
|
|
748
739
|
console.log(`Auth source: ${credential.source}`);
|
|
749
|
-
console.log(`API URL: ${
|
|
740
|
+
console.log(`API URL: ${resolveHostedApiUrl()}`);
|
|
750
741
|
console.log(
|
|
751
742
|
`LIBRETTO_API_KEY: ${envKey ? `set in env (${envKey.slice(0, 6)}…)` : "not set in env"}`,
|
|
752
743
|
);
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* them switch between any of the configured Subscription Update
|
|
7
7
|
* products (Free / Pro / Team).
|
|
8
8
|
*
|
|
9
|
-
* libretto
|
|
10
|
-
* libretto
|
|
9
|
+
* libretto cloud billing portal → Stripe Customer Portal
|
|
10
|
+
* libretto cloud billing status → plan + usage + period end
|
|
11
11
|
*
|
|
12
12
|
* `libretto init` is unchanged. New tenants start on Free automatically
|
|
13
13
|
* (with a real Stripe Customer + Free Subscription created at signup).
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* Auth: requires a session cookie (or LIBRETTO_API_KEY).
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { SimpleCLI } from "
|
|
18
|
+
import { SimpleCLI } from "affordance";
|
|
19
19
|
import {
|
|
20
20
|
NOT_AUTHENTICATED_MESSAGE,
|
|
21
21
|
orpcCall,
|
|
@@ -71,7 +71,6 @@ function formatLimit(limit: number | null): string {
|
|
|
71
71
|
|
|
72
72
|
export const billingPortalCommand = SimpleCLI.command({
|
|
73
73
|
description: "Open the libretto plans page (current plan + switch options)",
|
|
74
|
-
experimental: true,
|
|
75
74
|
})
|
|
76
75
|
.handle(async () => {
|
|
77
76
|
const { apiUrl, credential } = await requireAuth();
|
|
@@ -97,7 +96,6 @@ export const billingPortalCommand = SimpleCLI.command({
|
|
|
97
96
|
|
|
98
97
|
export const billingStatusCommand = SimpleCLI.command({
|
|
99
98
|
description: "Print the current plan, status, and browser-hour usage",
|
|
100
|
-
experimental: true,
|
|
101
99
|
})
|
|
102
100
|
.handle(async () => {
|
|
103
101
|
const { apiUrl, credential } = await requireAuth();
|