libretto 0.6.12 → 0.6.13

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 (46) hide show
  1. package/README.md +3 -8
  2. package/README.template.md +3 -8
  3. package/dist/cli/cli.js +0 -23
  4. package/dist/cli/commands/browser.js +1 -7
  5. package/dist/cli/commands/setup.js +1 -294
  6. package/dist/cli/commands/snapshot.js +9 -99
  7. package/dist/cli/commands/status.js +1 -41
  8. package/dist/cli/core/browser.js +3 -3
  9. package/dist/cli/core/config.js +3 -6
  10. package/dist/cli/core/daemon/daemon.js +25 -64
  11. package/dist/cli/core/daemon/snapshot.js +2 -29
  12. package/dist/cli/core/experiments.js +1 -28
  13. package/dist/cli/index.js +0 -2
  14. package/dist/cli/router.js +0 -2
  15. package/dist/shared/instrumentation/instrument.js +4 -4
  16. package/docs/releasing.md +8 -6
  17. package/package.json +2 -1
  18. package/skills/libretto/SKILL.md +17 -19
  19. package/skills/libretto/references/configuration-file-reference.md +6 -12
  20. package/skills/libretto/references/pages-and-page-targeting.md +1 -1
  21. package/skills/libretto-readonly/SKILL.md +2 -9
  22. package/src/cli/cli.ts +0 -24
  23. package/src/cli/commands/browser.ts +1 -7
  24. package/src/cli/commands/setup.ts +1 -380
  25. package/src/cli/commands/snapshot.ts +8 -136
  26. package/src/cli/commands/status.ts +1 -49
  27. package/src/cli/core/browser.ts +3 -3
  28. package/src/cli/core/config.ts +3 -6
  29. package/src/cli/core/daemon/daemon.ts +25 -67
  30. package/src/cli/core/daemon/ipc.ts +5 -16
  31. package/src/cli/core/daemon/snapshot.ts +1 -43
  32. package/src/cli/core/experiments.ts +9 -38
  33. package/src/cli/core/resolve-model.ts +5 -0
  34. package/src/cli/core/workflow-runtime.ts +1 -0
  35. package/src/cli/index.ts +0 -1
  36. package/src/cli/router.ts +0 -2
  37. package/src/shared/instrumentation/instrument.ts +4 -4
  38. package/dist/cli/commands/ai.js +0 -110
  39. package/dist/cli/core/ai-model.js +0 -195
  40. package/dist/cli/core/api-snapshot-analyzer.js +0 -86
  41. package/dist/cli/core/snapshot-analyzer.js +0 -667
  42. package/scripts/summarize-evals.mjs +0 -135
  43. package/src/cli/commands/ai.ts +0 -144
  44. package/src/cli/core/ai-model.ts +0 -301
  45. package/src/cli/core/api-snapshot-analyzer.ts +0 -110
  46. package/src/cli/core/snapshot-analyzer.ts +0 -856
@@ -3,7 +3,6 @@ import { dirname } from "node:path";
3
3
  import { z } from "zod";
4
4
  import { SessionAccessModeSchema } from "../../shared/state/index.js";
5
5
  import { LIBRETTO_CONFIG_PATH } from "./context.js";
6
- import { librettoCommand } from "../../shared/package-manager.js";
7
6
  const CURRENT_CONFIG_VERSION = 1;
8
7
  const ViewportConfigSchema = z.object({
9
8
  width: z.number().int().min(1),
@@ -29,7 +28,6 @@ function formatExpectedConfigExample() {
29
28
  return JSON.stringify(
30
29
  {
31
30
  version: CURRENT_CONFIG_VERSION,
32
- snapshotModel: "openai/gpt-5.4",
33
31
  viewport: {
34
32
  width: 1280,
35
33
  height: 800
@@ -53,10 +51,9 @@ ${detail}` : null,
53
51
  "Expected config example:",
54
52
  formatExpectedConfigExample(),
55
53
  "Notes:",
56
- ' - "snapshotModel", "viewport", "windowPosition", and "sessionMode" are optional.',
57
- ' - "snapshotModel" must be a provider/model string like "openai/gpt-5.4" or "anthropic/claude-sonnet-4-6".',
58
- "Fix the file to match this shape, or delete it and rerun:",
59
- ` ${librettoCommand("ai configure openai | anthropic | gemini | vertex | openrouter")}`
54
+ ' - "viewport", "windowPosition", and "sessionMode" are optional.',
55
+ ' - "snapshotModel" is deprecated and ignored by snapshot.',
56
+ "Fix the file to match this shape, or delete it and rerun setup."
60
57
  ].filter(Boolean).join("\n")
61
58
  );
62
59
  }
@@ -31,7 +31,7 @@ import {
31
31
  } from "../browser.js";
32
32
  import { handlePages } from "./pages.js";
33
33
  import { handleExec, handleReadonlyExec } from "./exec.js";
34
- import { handleCompactSnapshot, handleSnapshot } from "./snapshot.js";
34
+ import { handleCompactSnapshot } from "./snapshot.js";
35
35
  import { librettoCommand } from "../../../shared/package-manager.js";
36
36
  import { snapshot } from "../../../shared/snapshot/capture-snapshot.js";
37
37
  import { diffSnapshots } from "../../../shared/snapshot/diff-snapshots.js";
@@ -170,9 +170,7 @@ class BrowserDaemon {
170
170
  error: err instanceof Error ? err.message : String(err)
171
171
  });
172
172
  }
173
- if (experiments["compact-snapshot-format"]) {
174
- await context.addInitScript(installPageStabilityWaiter);
175
- }
173
+ await context.addInitScript(installPageStabilityWaiter);
176
174
  const socketPath = getDaemonSocketPath(session);
177
175
  const daemon = new BrowserDaemon(
178
176
  session,
@@ -188,19 +186,15 @@ class BrowserDaemon {
188
186
  wrapPageForActionLogging(p, session);
189
187
  daemon.trackPage(p);
190
188
  }
191
- if (experiments["compact-snapshot-format"]) {
192
- await Promise.all(
193
- initialPages.map(
194
- (initialPage) => daemon.installCompactSnapshotWaiter(initialPage)
195
- )
196
- );
197
- }
189
+ await Promise.all(
190
+ initialPages.map(
191
+ (initialPage) => daemon.installCompactSnapshotWaiter(initialPage)
192
+ )
193
+ );
198
194
  context.on("page", (newPage) => {
199
195
  wrapPageForActionLogging(newPage, session);
200
196
  daemon.trackPage(newPage);
201
- if (experiments["compact-snapshot-format"]) {
202
- void daemon.installCompactSnapshotWaiter(newPage);
203
- }
197
+ void daemon.installCompactSnapshotWaiter(newPage);
204
198
  });
205
199
  if (navigateUrl) {
206
200
  await page.goto(navigateUrl);
@@ -465,38 +459,23 @@ class BrowserDaemon {
465
459
  };
466
460
  }
467
461
  async runSnapshot(args) {
468
- if (args.mode === "compact") {
469
- if (!this.experiments["compact-snapshot-format"]) {
470
- throw new Error(
471
- `The compact-snapshot-format experiment is not enabled for session "${this.session}". Close and reopen the session after running ${librettoCommand("experiments enable compact-snapshot-format")}.`
472
- );
473
- }
474
- const targetPage = this.resolveTargetPage(args.pageId);
475
- const result = await this.withRequestTimeout(
476
- () => handleCompactSnapshot(
477
- targetPage,
478
- this.session,
479
- this.logger,
480
- {
481
- pageId: args.pageId,
482
- cachedSnapshot: this.latestCompactSnapshotByPage.get(targetPage),
483
- useCachedSnapshot: args.useCachedSnapshot
484
- }
485
- )
486
- );
487
- if (!args.useCachedSnapshot) {
488
- this.latestCompactSnapshotByPage.set(targetPage, result.snapshot);
489
- }
490
- return result;
491
- }
492
- return this.withRequestTimeout(
493
- () => handleSnapshot(
494
- this.resolveTargetPage(args.pageId),
462
+ const targetPage = this.resolveTargetPage(args.pageId);
463
+ const result = await this.withRequestTimeout(
464
+ () => handleCompactSnapshot(
465
+ targetPage,
495
466
  this.session,
496
467
  this.logger,
497
- args.pageId
468
+ {
469
+ pageId: args.pageId,
470
+ cachedSnapshot: this.latestCompactSnapshotByPage.get(targetPage),
471
+ useCachedSnapshot: args.useCachedSnapshot
472
+ }
498
473
  )
499
474
  );
475
+ if (!args.useCachedSnapshot) {
476
+ this.latestCompactSnapshotByPage.set(targetPage, result.snapshot);
477
+ }
478
+ return result;
500
479
  }
501
480
  async withRequestTimeout(operation) {
502
481
  let timerId;
@@ -513,25 +492,7 @@ class BrowserDaemon {
513
492
  }
514
493
  }
515
494
  async runExec(args) {
516
- if (this.experiments["compact-snapshot-format"]) {
517
- return this.runCompactExec(args);
518
- }
519
- try {
520
- const data = await this.withRequestTimeout(
521
- () => handleExec(
522
- this.resolveTargetPage(args.pageId),
523
- args.code,
524
- this.context,
525
- this.browser,
526
- this.execState,
527
- this.session,
528
- args.visualize
529
- )
530
- );
531
- return { ok: true, data };
532
- } catch (error) {
533
- return this.createExecErrorResult(error);
534
- }
495
+ return this.runCompactExec(args);
535
496
  }
536
497
  async runCompactExec(args) {
537
498
  let targetPage;
@@ -606,17 +567,17 @@ class BrowserDaemon {
606
567
  context: this.context,
607
568
  logger: this.logger,
608
569
  onLog: (event) => {
609
- this.broadcast("workflowOutput", event);
570
+ void this.broadcast("workflowOutput", event);
610
571
  },
611
572
  onOutcome: (outcome) => {
612
573
  if (outcome.state === "paused") {
613
- this.broadcast("workflowPaused", {
574
+ void this.broadcast("workflowPaused", {
614
575
  pausedAt: outcome.pausedAt,
615
576
  url: outcome.url
616
577
  });
617
578
  return;
618
579
  }
619
- this.broadcast(
580
+ void this.broadcast(
620
581
  "workflowFinished",
621
582
  outcome.result === "completed" ? { result: "completed", completedAt: outcome.completedAt } : {
622
583
  result: "failed",
@@ -1,4 +1,4 @@
1
- import { mkdirSync, writeFileSync } from "node:fs";
1
+ import { mkdirSync } from "node:fs";
2
2
  import { getSessionSnapshotRunDir } from "../context.js";
3
3
  import {
4
4
  snapshot
@@ -13,32 +13,6 @@ import {
13
13
  forceSnapshotViewport
14
14
  } from "../../commands/snapshot.js";
15
15
  const RENDER_SETTLE_TIMEOUT_MS = 1e4;
16
- async function handleSnapshot(targetPage, session, logger, pageId) {
17
- const screenshot = await captureSnapshotScreenshot(
18
- targetPage,
19
- session,
20
- logger,
21
- pageId
22
- );
23
- const htmlPath = `${getSessionSnapshotRunDir(
24
- session,
25
- screenshot.snapshotRunId
26
- )}/page.html`;
27
- const htmlContent = await targetPage.content();
28
- writeFileSync(htmlPath, htmlContent);
29
- logger.info("screenshot-success", {
30
- session,
31
- pageUrl: screenshot.pageUrl,
32
- title: screenshot.title,
33
- pngPath: screenshot.pngPath,
34
- htmlPath,
35
- snapshotRunId: screenshot.snapshotRunId
36
- });
37
- return {
38
- ...screenshot,
39
- htmlPath
40
- };
41
- }
42
16
  async function handleCompactSnapshot(targetPage, session, logger, options = {}) {
43
17
  if (options.useCachedSnapshot) {
44
18
  if (!options.cachedSnapshot) {
@@ -147,6 +121,5 @@ async function captureSnapshotScreenshot(targetPage, session, logger, pageId) {
147
121
  };
148
122
  }
149
123
  export {
150
- handleCompactSnapshot,
151
- handleSnapshot
124
+ handleCompactSnapshot
152
125
  };
@@ -2,34 +2,7 @@ import {
2
2
  readLibrettoConfig,
3
3
  writeLibrettoConfig
4
4
  } from "./config.js";
5
- const EXPERIMENTS = {
6
- "compact-snapshot-format": {
7
- title: "Compact snapshot format",
8
- oneSentenceDescription: "Use compact accessibility snapshots and exec page-change diffs without an AI sub-agent.",
9
- docs: [
10
- "Compact snapshot format changes how agents should use snapshot and exec after the experiment is enabled.",
11
- "",
12
- "Compared with the skill's documented behavior:",
13
- " - Run libretto snapshot --session <name> without --objective or --context.",
14
- " - Snapshot output is a screenshot path plus a compact accessibility tree; it does not use the PNG + HTML + AI analysis path.",
15
- " - Run libretto snapshot <ref> --session <name> to inspect a subtree from the latest full compact snapshot.",
16
- " - Run libretto exec normally; after successful mutations, Libretto prints page-change diffs from compact snapshots without AI analysis.",
17
- " - If a session was already open before enabling the experiment, close and reopen it before relying on this behavior.",
18
- "",
19
- "Full compact snapshot:",
20
- " libretto snapshot --session <name>",
21
- "",
22
- "Cached subtree snapshot:",
23
- " libretto snapshot <ref> --session <name>",
24
- "",
25
- "Run an unscoped snapshot before using refs. Subtree snapshots capture a fresh screenshot but reuse the latest cached tree.",
26
- "",
27
- "Notes:",
28
- " - Use ref forms printed in the tree, such as l16. Numeric-suffix aliases such as e16 also match l16."
29
- ].join("\n"),
30
- defaultValue: false
31
- }
32
- };
5
+ const EXPERIMENTS = {};
33
6
  function isExperimentName(name) {
34
7
  return Object.hasOwn(EXPERIMENTS, name);
35
8
  }
package/dist/cli/index.js CHANGED
@@ -1,8 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { runLibrettoCLI } from "./cli.js";
3
- import { runClose } from "./commands/browser.js";
4
3
  void runLibrettoCLI();
5
4
  export {
6
- runClose,
7
5
  runLibrettoCLI
8
6
  };
@@ -1,4 +1,3 @@
1
- import { aiCommands } from "./commands/ai.js";
2
1
  import { authCommands } from "./commands/auth.js";
3
2
  import { billingCommands } from "./commands/billing.js";
4
3
  import { browserCommands } from "./commands/browser.js";
@@ -15,7 +14,6 @@ const cliRoutes = {
15
14
  deploy: deployCommand,
16
15
  experiments: experimentsCommand,
17
16
  ...executionCommands,
18
- ai: aiCommands,
19
17
  auth: authCommands,
20
18
  billing: billingCommands,
21
19
  setup: setupCommand,
@@ -82,12 +82,12 @@ function wrapLocatorActions(locator, page, opts) {
82
82
  try {
83
83
  const result = await orig(...args);
84
84
  if (opts.visualize) {
85
- enqueue(page, () => visualizeAfterAction(page));
85
+ void enqueue(page, () => visualizeAfterAction(page));
86
86
  }
87
87
  return result;
88
88
  } catch (err) {
89
89
  if (opts.visualize) {
90
- enqueue(page, () => visualizeAfterAction(page));
90
+ void enqueue(page, () => visualizeAfterAction(page));
91
91
  }
92
92
  if (POINTER_ACTIONS.has(method) && isTimeoutError(err)) {
93
93
  await enrichTimeoutError(err, locator, page);
@@ -226,12 +226,12 @@ async function installInstrumentation(page, options) {
226
226
  try {
227
227
  const result = await orig(...args);
228
228
  if (visualize) {
229
- enqueue(page, () => visualizeAfterAction(page));
229
+ void enqueue(page, () => visualizeAfterAction(page));
230
230
  }
231
231
  return result;
232
232
  } catch (err) {
233
233
  if (visualize) {
234
- enqueue(page, () => visualizeAfterAction(page));
234
+ void enqueue(page, () => visualizeAfterAction(page));
235
235
  }
236
236
  if (POINTER_ACTIONS.has(method) && isTimeoutError(err) && typeof args[0] === "string") {
237
237
  await enrichTimeoutError(err, page.locator(args[0]), page);
package/docs/releasing.md CHANGED
@@ -24,7 +24,7 @@ This repo does not publish from local machines and does not push directly to `ma
24
24
 
25
25
  GitHub Actions needs these repository secrets:
26
26
 
27
- - `OPENAI_API_KEY`: used by the existing test suite during the release workflow.
27
+ - `OPENAI_API_KEY`: used by the existing test suite during the release workflow and by the eval workflow's default `openai/gpt-5.5` model.
28
28
 
29
29
  The release workflow uses a GitHub Actions environment named `release`. Create that environment in the repository settings (no required reviewers — access is controlled by branch protection on `main` instead).
30
30
 
@@ -69,7 +69,7 @@ The root `scripts/prepare-release.sh` script does the following:
69
69
  6. Commits the version bump.
70
70
  7. Pushes the branch and opens a PR to `main` with the `release` label.
71
71
 
72
- Release PRs also run the eval workflow. That workflow compares the current eval score against the latest successful `main` baseline and fails if the score drifts by more than 5 percentage points in either direction.
72
+ Release PRs also run the eval workflow. That workflow records score, duration, token, cost, and tool-call metrics for review. Scores are informational: low scores do not fail the workflow, but setup/runtime failures and zero completed records do.
73
73
 
74
74
  ## Merge behavior
75
75
 
@@ -89,11 +89,13 @@ This makes the workflow safe to re-run after partial failures. For example, if n
89
89
 
90
90
  `.github/workflows/evals.yml` now runs automatically for release PRs and for qualifying pushes to `main`.
91
91
 
92
- - On `main`, it records the current eval summary as the baseline artifact for future release PRs.
93
- - On release PRs, it runs evals again and compares the overall score against the latest successful `main` baseline.
94
- - If the score moves outside a `+/-5%` window, the eval job fails and flags the release PR.
92
+ - It runs `pnpm evals --no-auth --output <runner-temp>/eval-run` so CI only runs cases that do not require local auth profiles.
93
+ - It validates and renders the CI report with `pnpm evals summary <runner-temp>/eval-run`.
94
+ - It writes a GitHub step summary and a sticky PR comment with aggregate score, duration, token, cost, and tool-call metrics.
95
+ - It uploads summary files and per-case result records from the run output directory. Raw transcripts and local profile files are not uploaded.
96
+ - It fails when the eval runner crashes, required setup is missing, result records are malformed, or zero completed records are produced.
95
97
 
96
- If no successful baseline artifact exists yet, the release PR eval job reports that and skips the comparison for that run.
98
+ There is no baseline comparison gate yet. Add one only after the eval records and metrics are stable enough to compare reliably.
97
99
 
98
100
  ## Changelog behavior
99
101
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "libretto",
3
- "version": "0.6.12",
3
+ "version": "0.6.13",
4
4
  "description": "AI-powered browser automation library and CLI built on Playwright",
5
5
  "license": "MIT",
6
6
  "homepage": "https://libretto.sh",
@@ -37,6 +37,7 @@
37
37
  "sync-skills": "pnpm run sync:mirrors",
38
38
  "check:skills": "pnpm run check:mirrors",
39
39
  "build": "tsup --config tsup.config.ts",
40
+ "lint": "lintcn lint --tsconfig tsconfig.json",
40
41
  "type-check": "tsc --noEmit",
41
42
  "test": "turbo run test:vitest --filter=libretto --log-order=grouped",
42
43
  "test:vitest": "vitest run",
@@ -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.12"
7
+ version: "0.6.13"
8
8
  ---
9
9
 
10
10
  ## How Libretto Works
@@ -34,10 +34,12 @@ Full documentation is published at [libretto.sh](https://libretto.sh). Available
34
34
 
35
35
  ## Setup
36
36
 
37
- - Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium, syncs skills, and pins the default snapshot model to `.libretto/config.json` when provider credentials are available.
38
- - Re-running `setup` on a healthy workspace shows the current configuration. If credentials are missing for a configured provider, it offers an interactive repair flow.
39
- - Use `npx libretto status` to inspect AI configuration health and open sessions without triggering setup.
40
- - Use `npx libretto ai configure openai|anthropic|gemini|vertex` to explicitly change the snapshot model or provider (advanced override).
37
+ - Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium and syncs skills.
38
+ - Use `npx libretto status` to inspect open sessions without triggering setup.
39
+
40
+ ## Experiments
41
+
42
+ - Use `npx libretto experiments` to list internal feature flags and `npx libretto experiments describe <name>` for usage notes when an experiment is enabled.
41
43
 
42
44
  ## Working Rules
43
45
 
@@ -95,20 +97,15 @@ npx libretto session-mode --session my-session
95
97
  ### `snapshot`
96
98
 
97
99
  - Use `snapshot` as the primary page observation tool.
98
- - Always provide both `--objective` and `--context`.
99
- - A single snapshot objective can include multiple questions or analysis tasks.
100
+ - Run `snapshot` without `--objective` or `--context`; the command prints a screenshot path and compact accessibility tree for the current page.
101
+ - 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`.
102
+ - Run an unscoped snapshot before using refs. Subtree snapshots capture a fresh screenshot but reuse the latest cached tree.
100
103
  - 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
104
 
103
105
  ```bash
104
- npx libretto snapshot \
105
- --objective "Find the sign-in form and submit button" \
106
- --context "I just opened the login page and need the email field, password field, and submit button."
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."
106
+ npx libretto snapshot --session debug-example
107
+ npx libretto snapshot <ref> --session debug-example
108
+ npx libretto snapshot --session debug-example --page <page-id>
112
109
  ```
113
110
 
114
111
  ### `exec`
@@ -120,6 +117,7 @@ npx libretto snapshot \
120
117
  - Let failures throw. Do not hide `exec` failures with `try/catch` or `.catch()`.
121
118
  - Do not run multiple `exec` commands in parallel.
122
119
  - Do not use `exec` in read-only diagnosis flows. Use `readonly-exec` from the `libretto-readonly` skill for those sessions.
120
+ - After successful mutations, `exec` prints page-change diffs from compact snapshots.
123
121
 
124
122
  ```bash
125
123
  npx libretto exec "return await page.url()"
@@ -227,7 +225,7 @@ Key fields: `ts` (ISO timestamp), `method` (HTTP method, e.g. `GET`, `POST`), `u
227
225
  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
226
  Assistant: [Runs `npx libretto open https://target.example.com --headed`]
229
227
  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 --objective "Find the next required action" --context "We are starting the workflow from the landing page and need the first meaningful step."`]
228
+ Assistant: [Runs `npx libretto snapshot --session <session>`]
231
229
  Assistant: [Uses `snapshot` and `exec` as needed to understand the site and decide the implementation path]
232
230
  Assistant: [Reads `references/code-generation-rules.md` before writing production workflow code]
233
231
  Assistant: I found the working path. I'll now create the workflow file and verify it.
@@ -247,7 +245,7 @@ To watch it yourself in a browser, run: npx libretto run ./target-workflow.ts --
247
245
  Assistant: I'll reproduce the failure first so we can inspect the exact browser state it leaves behind.
248
246
  Assistant: [Runs `npx libretto run ./integration.ts --session debug-flow --headed`]
249
247
  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 --objective "Find the blocking error or broken selector target" --context "The workflow just failed after trying to continue from the review step, and I need to identify the visible blocker on the current page."`]
248
+ Assistant: [Runs `npx libretto snapshot --session debug-flow`]
251
249
  Assistant: [Runs `npx libretto exec --session debug-flow "...focused inspection or prototype..."`]
252
250
  Assistant: [Reads `references/code-generation-rules.md` before patching the workflow file]
253
251
  Assistant: I found the issue. I'll patch the workflow code and verify.
@@ -261,7 +259,7 @@ To watch it yourself in a browser, run: npx libretto run ./integration.ts --head
261
259
 
262
260
  ## References
263
261
 
264
- - Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for snapshot model selection or viewport defaults.
262
+ - Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for viewport or session defaults.
265
263
  - 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
264
  - Read `references/code-generation-rules.md` before writing or editing production workflow files.
267
265
  - Read `references/auth-profiles.md` when auth-profile behavior is relevant.
@@ -1,10 +1,9 @@
1
1
  # Configuration File Reference
2
2
 
3
- Use this reference when you need to inspect or change the workspace configuration that powers `snapshot` analysis and default viewport behavior.
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`.
10
9
 
@@ -12,14 +11,12 @@ Use this reference when you need to inspect or change the workspace configuratio
12
11
 
13
12
  Libretto reads workspace config from `.libretto/config.json`.
14
13
 
15
- - The file is created by `npx libretto setup` during first-time onboarding (auto-pins the default model for the detected provider) or by `npx libretto ai configure ...` for explicit overrides.
16
- - API credentials come from your shell environment or a `.env` file **at the repository root** (next to your `.git` directory). The config file stores the selected model, not the secret itself. Set `LIBRETTO_DISABLE_DOTENV=1` to skip `.env` loading (useful in CI).
17
- - Use `npx libretto status` to inspect the current AI configuration and open sessions without changing anything.
14
+ - The file is created by `npx libretto setup` during first-time onboarding.
15
+ - Use `npx libretto status` to inspect open sessions without changing anything.
18
16
  - For first-time setup instructions, follow the main `SKILL.md` flow instead of expanding this reference.
19
17
 
20
18
  ## Supported Settings
21
19
 
22
- - `snapshotModel` selects the configured analysis model for `snapshot`.
23
20
  - `viewport` is an optional top-level setting used by `open` and `run` when you do not pass `--viewport`.
24
21
  - Viewport precedence is: CLI `--viewport`, then `.libretto/config.json`, then the default `1366x768`.
25
22
  - `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 +26,6 @@ Example:
29
26
  ```json
30
27
  {
31
28
  "version": 1,
32
- "snapshotModel": "openai/gpt-5.4",
33
29
  "viewport": {
34
30
  "width": 1280,
35
31
  "height": 800
@@ -41,9 +37,8 @@ Example:
41
37
  ## Common Commands
42
38
 
43
39
  ```bash
44
- npx libretto setup # first-time onboarding, auto-pins default model
45
- npx libretto status # inspect AI config and open sessions
46
- npx libretto ai configure openai # explicitly change provider/model
40
+ npx libretto setup # first-time onboarding
41
+ npx libretto status # inspect open sessions
47
42
  npx libretto open https://example.com --viewport 1440x900
48
43
  npx libretto run ./integration.ts --viewport 1440x900
49
44
  ```
@@ -51,5 +46,4 @@ npx libretto run ./integration.ts --viewport 1440x900
51
46
  ## Notes
52
47
 
53
48
  - If you want a persistent default viewport for the workspace, add `viewport` to `.libretto/config.json` instead of repeating `--viewport` on every command.
54
- - If `snapshot` analysis is not configured yet, run `npx libretto setup` to auto-configure, or see the main `SKILL.md` flow.
55
- - Run `npx libretto status` at any time to check which model is active and whether credentials are present.
49
+ - 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> --objective "Find the active form"
22
+ npx libretto snapshot --session debug-flow --page <page-id>
23
23
  ```
24
24
 
25
25
  ## Notes
@@ -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.12"
7
+ version: "0.6.13"
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
- - Always provide both `--objective` and `--context`.
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 {
@@ -11,7 +11,7 @@ import {
11
11
  } from "../core/browser.js";
12
12
  import { resolveProviderName } from "../core/providers/index.js";
13
13
  import { readLibrettoConfig } from "../core/config.js";
14
- import { createLoggerForSession, withSessionLogger } from "../core/context.js";
14
+ import { createLoggerForSession } from "../core/context.js";
15
15
  import { librettoCommand } from "../../shared/package-manager.js";
16
16
  import {
17
17
  type SessionAccessMode,
@@ -295,9 +295,3 @@ export const browserCommands = {
295
295
  "session-mode": sessionModeCommand,
296
296
  close: closeCommand,
297
297
  };
298
-
299
- export async function runClose(session: string): Promise<void> {
300
- await withSessionLogger(session, async (logger) => {
301
- await runCloseWithLogger(session, logger);
302
- });
303
- }