libretto 0.5.5 → 0.5.6
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 +23 -10
- package/README.template.md +23 -10
- package/dist/cli/cli.js +10 -0
- package/dist/cli/commands/ai.js +77 -2
- package/dist/cli/commands/browser.js +71 -6
- package/dist/cli/commands/execution.js +101 -44
- package/dist/cli/commands/setup.js +376 -0
- package/dist/cli/commands/snapshot.js +2 -2
- package/dist/cli/commands/status.js +62 -0
- package/dist/cli/core/{snapshot-api-config.js → ai-model.js} +81 -7
- package/dist/cli/core/api-snapshot-analyzer.js +7 -5
- package/dist/cli/core/browser.js +39 -26
- package/dist/cli/core/{ai-config.js → config.js} +13 -79
- package/dist/cli/core/context.js +1 -25
- package/dist/cli/core/deploy-artifact.js +121 -61
- package/dist/cli/core/readonly-exec.js +231 -0
- package/dist/{shared/llm/client.js → cli/core/resolve-model.js} +4 -68
- package/dist/cli/core/session.js +44 -0
- package/dist/cli/core/skill-version.js +73 -0
- package/dist/cli/core/telemetry.js +1 -54
- package/dist/cli/index.js +1 -7
- package/dist/cli/router.js +4 -4
- package/dist/cli/workers/run-integration-runtime.js +17 -13
- package/dist/cli/workers/run-integration-worker-protocol.js +3 -2
- package/dist/index.d.ts +2 -4
- package/dist/index.js +2 -2
- package/dist/runtime/extract/extract.d.ts +2 -2
- package/dist/runtime/extract/extract.js +4 -2
- package/dist/runtime/extract/index.d.ts +1 -1
- package/dist/runtime/recovery/agent.d.ts +2 -3
- package/dist/runtime/recovery/agent.js +5 -3
- package/dist/runtime/recovery/errors.d.ts +2 -3
- package/dist/runtime/recovery/errors.js +4 -2
- package/dist/runtime/recovery/index.d.ts +1 -2
- package/dist/runtime/recovery/recovery.d.ts +2 -3
- package/dist/runtime/recovery/recovery.js +3 -3
- package/dist/shared/debug/pause.js +4 -21
- package/dist/shared/run/api.d.ts +2 -0
- package/dist/shared/run/browser.d.ts +4 -1
- package/dist/shared/run/browser.js +5 -3
- package/dist/shared/state/index.d.ts +1 -1
- package/dist/shared/state/index.js +2 -0
- package/dist/shared/state/session-state.d.ts +10 -1
- package/dist/shared/state/session-state.js +3 -0
- package/dist/shared/workflow/workflow.d.ts +2 -1
- package/dist/shared/workflow/workflow.js +16 -9
- package/package.json +17 -16
- package/scripts/postinstall.mjs +13 -11
- package/scripts/skills-libretto.mjs +14 -4
- package/skills/AGENTS.md +11 -0
- package/skills/libretto/SKILL.md +30 -9
- package/skills/libretto/references/auth-profiles.md +1 -1
- package/skills/libretto/references/code-generation-rules.md +3 -3
- package/skills/libretto/references/configuration-file-reference.md +11 -6
- package/skills/libretto-readonly/SKILL.md +95 -0
- package/src/cli/cli.ts +10 -0
- package/src/cli/commands/ai.ts +111 -1
- package/src/cli/commands/browser.ts +81 -7
- package/src/cli/commands/execution.ts +128 -61
- package/src/cli/commands/setup.ts +499 -0
- package/src/cli/commands/snapshot.ts +2 -2
- package/src/cli/commands/status.ts +77 -0
- package/src/cli/core/{snapshot-api-config.ts → ai-model.ts} +154 -14
- package/src/cli/core/api-snapshot-analyzer.ts +7 -5
- package/src/cli/core/browser.ts +45 -26
- package/src/cli/core/{ai-config.ts → config.ts} +13 -108
- package/src/cli/core/context.ts +1 -45
- package/src/cli/core/deploy-artifact.ts +141 -71
- package/src/cli/core/readonly-exec.ts +284 -0
- package/src/{shared/llm/client.ts → cli/core/resolve-model.ts} +3 -85
- package/src/cli/core/session.ts +62 -2
- package/src/cli/core/skill-version.ts +93 -0
- package/src/cli/core/telemetry.ts +0 -52
- package/src/cli/index.ts +0 -6
- package/src/cli/router.ts +4 -4
- package/src/cli/workers/run-integration-runtime.ts +16 -16
- package/src/cli/workers/run-integration-worker-protocol.ts +2 -1
- package/src/index.ts +1 -7
- package/src/runtime/extract/extract.ts +6 -5
- package/src/runtime/recovery/agent.ts +5 -4
- package/src/runtime/recovery/errors.ts +4 -3
- package/src/runtime/recovery/recovery.ts +4 -4
- package/src/shared/debug/pause.ts +4 -23
- package/src/shared/run/browser.ts +5 -1
- package/src/shared/state/index.ts +2 -0
- package/src/shared/state/session-state.ts +3 -0
- package/src/shared/workflow/workflow.ts +24 -13
- package/dist/cli/commands/init.js +0 -286
- package/dist/cli/commands/logs.js +0 -117
- package/dist/shared/llm/ai-sdk-adapter.d.ts +0 -22
- package/dist/shared/llm/ai-sdk-adapter.js +0 -49
- package/dist/shared/llm/client.d.ts +0 -13
- package/dist/shared/llm/index.d.ts +0 -5
- package/dist/shared/llm/index.js +0 -6
- package/dist/shared/llm/types.d.ts +0 -67
- package/dist/shared/llm/types.js +0 -0
- package/src/cli/commands/init.ts +0 -331
- package/src/cli/commands/logs.ts +0 -128
- package/src/shared/llm/ai-sdk-adapter.ts +0 -81
- package/src/shared/llm/index.ts +0 -3
- package/src/shared/llm/types.ts +0 -63
package/README.md
CHANGED
|
@@ -22,13 +22,20 @@ https://github.com/user-attachments/assets/9b9a0ab3-5133-4b20-b3be-459943349d18
|
|
|
22
22
|
```bash
|
|
23
23
|
npm install libretto
|
|
24
24
|
|
|
25
|
-
#
|
|
26
|
-
npx libretto
|
|
25
|
+
# First-time onboarding: install skill, download Chromium, and pin the default snapshot model
|
|
26
|
+
npx libretto setup
|
|
27
27
|
|
|
28
|
-
#
|
|
28
|
+
# Check workspace readiness at any time
|
|
29
|
+
npx libretto status
|
|
30
|
+
|
|
31
|
+
# Manually change the snapshot analysis model (advanced override)
|
|
29
32
|
npx libretto ai configure <openai | anthropic | gemini | vertex>
|
|
30
33
|
```
|
|
31
34
|
|
|
35
|
+
`setup` detects available provider credentials (e.g. `OPENAI_API_KEY`) and automatically pins the default model to `.libretto/config.json`. Re-running `setup` on a healthy workspace shows the current configuration instead of re-prompting. If credentials are missing for a previously configured provider, `setup` offers an interactive repair flow.
|
|
36
|
+
|
|
37
|
+
Use `ai configure` when you want to explicitly switch providers or set a custom model string.
|
|
38
|
+
|
|
32
39
|
## Use cases
|
|
33
40
|
|
|
34
41
|
Libretto is designed to be used as a skill through your coding agent. Here are some example prompts:
|
|
@@ -62,19 +69,19 @@ Agents can use Libretto to reproduce the failure, pause the workflow at any poin
|
|
|
62
69
|
You can also use Libretto directly from the command line. All commands accept `--session <name>` to target a specific session.
|
|
63
70
|
|
|
64
71
|
```bash
|
|
65
|
-
npx libretto
|
|
72
|
+
npx libretto setup # interactive first-run onboarding; run yourself, not through an agent
|
|
73
|
+
npx libretto status # check AI config health and open sessions
|
|
66
74
|
npx libretto open <url> # launch browser and open a URL (headed by default)
|
|
67
75
|
npx libretto snapshot --objective "..." --context "..." # capture PNG + HTML and analyze with an LLM
|
|
68
76
|
npx libretto exec "<code>" # execute Playwright TypeScript against the open page (single quoted argument)
|
|
69
77
|
echo "<code>" | npx libretto exec - # intentionally read Playwright TypeScript from stdin
|
|
70
|
-
npx libretto run <file>
|
|
78
|
+
npx libretto run <file> # run the file's default-exported workflow
|
|
71
79
|
npx libretto resume # resume a paused workflow
|
|
72
|
-
npx libretto network # view captured network requests
|
|
73
|
-
npx libretto actions # view captured user/agent actions
|
|
74
80
|
npx libretto pages # list open pages in the session
|
|
75
81
|
npx libretto save <domain> # save browser session (cookies, localStorage) for reuse
|
|
76
82
|
npx libretto close # close the browser
|
|
77
|
-
npx libretto ai configure <provider> #
|
|
83
|
+
npx libretto ai configure <provider> # manually change snapshot analysis model
|
|
84
|
+
npx libretto status # show AI config and open sessions
|
|
78
85
|
```
|
|
79
86
|
|
|
80
87
|
## Configuration
|
|
@@ -98,12 +105,18 @@ All Libretto state lives in a `.libretto/` directory at your project root. Confi
|
|
|
98
105
|
|
|
99
106
|
The `ai` field configures which model Libretto uses for snapshot analysis — extracting selectors, identifying interactive elements, or diagnosing why a step failed. This keeps heavy visual context out of your coding agent's context window. Snapshot analysis is required.
|
|
100
107
|
|
|
101
|
-
|
|
108
|
+
`npx libretto setup` automatically pins the default model for the first provider whose credentials it finds. To explicitly change the provider or model afterward:
|
|
102
109
|
|
|
103
110
|
```bash
|
|
104
111
|
npx libretto ai configure <openai | anthropic | gemini | vertex>
|
|
105
112
|
```
|
|
106
113
|
|
|
114
|
+
To inspect the current configuration without changing anything:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx libretto status
|
|
118
|
+
```
|
|
119
|
+
|
|
107
120
|
Provider credentials are read from environment variables or a `.env` file at your project root: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY`, or `GOOGLE_CLOUD_PROJECT` for Vertex.
|
|
108
121
|
|
|
109
122
|
The `viewport` field sets the default browser viewport size. Both fields are optional.
|
|
@@ -157,6 +170,6 @@ Source layout:
|
|
|
157
170
|
- `README.template.md` — source of truth for the repo and package READMEs
|
|
158
171
|
- `skills/libretto/` — source of truth for the Libretto skill
|
|
159
172
|
|
|
160
|
-
Run `pnpm sync:mirrors` after editing `README.template.md` or anything under `skills/libretto/`.
|
|
173
|
+
Run `pnpm sync:mirrors` after editing `README.template.md` or anything under `skills/libretto/`.
|
|
161
174
|
|
|
162
175
|
To check that generated READMEs, skill mirrors, and skill version metadata are in sync without fixing them, run `pnpm check:mirrors`. To release, run `pnpm prepare-release`.
|
package/README.template.md
CHANGED
|
@@ -20,13 +20,20 @@ https://github.com/user-attachments/assets/9b9a0ab3-5133-4b20-b3be-459943349d18
|
|
|
20
20
|
```bash
|
|
21
21
|
npm install libretto
|
|
22
22
|
|
|
23
|
-
#
|
|
24
|
-
npx libretto
|
|
23
|
+
# First-time onboarding: install skill, download Chromium, and pin the default snapshot model
|
|
24
|
+
npx libretto setup
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Check workspace readiness at any time
|
|
27
|
+
npx libretto status
|
|
28
|
+
|
|
29
|
+
# Manually change the snapshot analysis model (advanced override)
|
|
27
30
|
npx libretto ai configure <openai | anthropic | gemini | vertex>
|
|
28
31
|
```
|
|
29
32
|
|
|
33
|
+
`setup` detects available provider credentials (e.g. `OPENAI_API_KEY`) and automatically pins the default model to `.libretto/config.json`. Re-running `setup` on a healthy workspace shows the current configuration instead of re-prompting. If credentials are missing for a previously configured provider, `setup` offers an interactive repair flow.
|
|
34
|
+
|
|
35
|
+
Use `ai configure` when you want to explicitly switch providers or set a custom model string.
|
|
36
|
+
|
|
30
37
|
## Use cases
|
|
31
38
|
|
|
32
39
|
Libretto is designed to be used as a skill through your coding agent. Here are some example prompts:
|
|
@@ -60,19 +67,19 @@ Agents can use Libretto to reproduce the failure, pause the workflow at any poin
|
|
|
60
67
|
You can also use Libretto directly from the command line. All commands accept `--session <name>` to target a specific session.
|
|
61
68
|
|
|
62
69
|
```bash
|
|
63
|
-
npx libretto
|
|
70
|
+
npx libretto setup # interactive first-run onboarding; run yourself, not through an agent
|
|
71
|
+
npx libretto status # check AI config health and open sessions
|
|
64
72
|
npx libretto open <url> # launch browser and open a URL (headed by default)
|
|
65
73
|
npx libretto snapshot --objective "..." --context "..." # capture PNG + HTML and analyze with an LLM
|
|
66
74
|
npx libretto exec "<code>" # execute Playwright TypeScript against the open page (single quoted argument)
|
|
67
75
|
echo "<code>" | npx libretto exec - # intentionally read Playwright TypeScript from stdin
|
|
68
|
-
npx libretto run <file>
|
|
76
|
+
npx libretto run <file> # run the file's default-exported workflow
|
|
69
77
|
npx libretto resume # resume a paused workflow
|
|
70
|
-
npx libretto network # view captured network requests
|
|
71
|
-
npx libretto actions # view captured user/agent actions
|
|
72
78
|
npx libretto pages # list open pages in the session
|
|
73
79
|
npx libretto save <domain> # save browser session (cookies, localStorage) for reuse
|
|
74
80
|
npx libretto close # close the browser
|
|
75
|
-
npx libretto ai configure <provider> #
|
|
81
|
+
npx libretto ai configure <provider> # manually change snapshot analysis model
|
|
82
|
+
npx libretto status # show AI config and open sessions
|
|
76
83
|
```
|
|
77
84
|
|
|
78
85
|
## Configuration
|
|
@@ -96,12 +103,18 @@ All Libretto state lives in a `.libretto/` directory at your project root. Confi
|
|
|
96
103
|
|
|
97
104
|
The `ai` field configures which model Libretto uses for snapshot analysis — extracting selectors, identifying interactive elements, or diagnosing why a step failed. This keeps heavy visual context out of your coding agent's context window. Snapshot analysis is required.
|
|
98
105
|
|
|
99
|
-
|
|
106
|
+
`npx libretto setup` automatically pins the default model for the first provider whose credentials it finds. To explicitly change the provider or model afterward:
|
|
100
107
|
|
|
101
108
|
```bash
|
|
102
109
|
npx libretto ai configure <openai | anthropic | gemini | vertex>
|
|
103
110
|
```
|
|
104
111
|
|
|
112
|
+
To inspect the current configuration without changing anything:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npx libretto status
|
|
116
|
+
```
|
|
117
|
+
|
|
105
118
|
Provider credentials are read from environment variables or a `.env` file at your project root: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GEMINI_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY`, or `GOOGLE_CLOUD_PROJECT` for Vertex.
|
|
106
119
|
|
|
107
120
|
The `viewport` field sets the default browser viewport size. Both fields are optional.
|
|
@@ -155,6 +168,6 @@ Source layout:
|
|
|
155
168
|
- `{{LIBRETTO_PATH_PREFIX}}README.template.md` — source of truth for the repo and package READMEs
|
|
156
169
|
- `{{LIBRETTO_PATH_PREFIX}}skills/libretto/` — source of truth for the Libretto skill
|
|
157
170
|
|
|
158
|
-
Run `pnpm sync:mirrors` after editing `{{LIBRETTO_PATH_PREFIX}}README.template.md` or anything under `{{LIBRETTO_PATH_PREFIX}}skills/libretto/`.
|
|
171
|
+
Run `pnpm sync:mirrors` after editing `{{LIBRETTO_PATH_PREFIX}}README.template.md` or anything under `{{LIBRETTO_PATH_PREFIX}}skills/libretto/`.
|
|
159
172
|
|
|
160
173
|
To check that generated READMEs, skill mirrors, and skill version metadata are in sync without fixing them, run `pnpm check:mirrors`. To release, run `pnpm prepare-release`.
|
package/dist/cli/cli.js
CHANGED
|
@@ -15,6 +15,10 @@ Examples:
|
|
|
15
15
|
|
|
16
16
|
libretto exec "await page.locator('button:has-text(\\"Sign in\\")').click()"
|
|
17
17
|
libretto exec "await page.fill('input[name=\\"email\\"]', 'test@example.com')"
|
|
18
|
+
libretto readonly-exec "return await page.title()" --session test1
|
|
19
|
+
libretto connect http://127.0.0.1:9222 --read-only --session test1
|
|
20
|
+
libretto run ./integration.ts --read-only --session test1
|
|
21
|
+
libretto status
|
|
18
22
|
libretto ai configure openai
|
|
19
23
|
libretto ai configure anthropic
|
|
20
24
|
libretto ai configure gemini
|
|
@@ -35,6 +39,9 @@ Examples:
|
|
|
35
39
|
Available in exec:
|
|
36
40
|
page, context, state, browser, networkLog, actionLog
|
|
37
41
|
|
|
42
|
+
Available in readonly-exec:
|
|
43
|
+
page, state, snapshot, scrollBy, get
|
|
44
|
+
|
|
38
45
|
Profiles:
|
|
39
46
|
Profiles are saved to .libretto/profiles/<domain>.json (git-ignored)
|
|
40
47
|
They persist cookies, localStorage, and session data across browser launches.
|
|
@@ -45,6 +52,9 @@ Sessions:
|
|
|
45
52
|
Session state is stored in .libretto/sessions/<session>/state.json
|
|
46
53
|
CLI logs are stored in .libretto/sessions/<session>/logs.jsonl
|
|
47
54
|
Each session runs an isolated browser instance on a dynamic port.
|
|
55
|
+
Session mode is stored per session as read-only or write-access.
|
|
56
|
+
Use --read-only on open, connect, or run to create a read-only session.
|
|
57
|
+
Session mode is enforced by Libretto commands, not by raw CDP clients outside Libretto.
|
|
48
58
|
`;
|
|
49
59
|
}
|
|
50
60
|
function isRootHelpRequest(rawArgs) {
|
package/dist/cli/commands/ai.js
CHANGED
|
@@ -1,6 +1,80 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
readAiConfig,
|
|
4
|
+
writeAiConfig,
|
|
5
|
+
clearAiConfig
|
|
6
|
+
} from "../core/config.js";
|
|
7
|
+
import { LIBRETTO_CONFIG_PATH } from "../core/context.js";
|
|
8
|
+
import { DEFAULT_SNAPSHOT_MODELS } from "../core/ai-model.js";
|
|
3
9
|
import { SimpleCLI } from "../framework/simple-cli.js";
|
|
10
|
+
const PROVIDER_ALIASES = {
|
|
11
|
+
claude: DEFAULT_SNAPSHOT_MODELS.anthropic,
|
|
12
|
+
gemini: DEFAULT_SNAPSHOT_MODELS.google,
|
|
13
|
+
google: DEFAULT_SNAPSHOT_MODELS.google
|
|
14
|
+
};
|
|
15
|
+
const CONFIGURE_PROVIDERS = [
|
|
16
|
+
"openai",
|
|
17
|
+
"anthropic",
|
|
18
|
+
"gemini",
|
|
19
|
+
"vertex"
|
|
20
|
+
];
|
|
21
|
+
function formatConfigureProviders(separator = " | ") {
|
|
22
|
+
return CONFIGURE_PROVIDERS.join(separator);
|
|
23
|
+
}
|
|
24
|
+
function printAiConfig(config, configPath) {
|
|
25
|
+
console.log(`Model: ${config.model}`);
|
|
26
|
+
console.log(`Config file: ${configPath}`);
|
|
27
|
+
console.log(`Updated at: ${config.updatedAt}`);
|
|
28
|
+
}
|
|
29
|
+
function resolveModelFromInput(input) {
|
|
30
|
+
const trimmed = input.trim();
|
|
31
|
+
if (!trimmed) return null;
|
|
32
|
+
if (trimmed.includes("/")) return trimmed;
|
|
33
|
+
const normalized = trimmed.toLowerCase();
|
|
34
|
+
return DEFAULT_SNAPSHOT_MODELS[normalized] ?? PROVIDER_ALIASES[normalized] ?? null;
|
|
35
|
+
}
|
|
36
|
+
function runAiConfigure(input, options = {}) {
|
|
37
|
+
const configureCommandName = options.configureCommandName ?? "npx libretto ai configure";
|
|
38
|
+
const configPath = options.configPath ?? LIBRETTO_CONFIG_PATH;
|
|
39
|
+
const presetArg = input.preset?.trim();
|
|
40
|
+
if (!presetArg && !input.clear) {
|
|
41
|
+
const config2 = readAiConfig(configPath);
|
|
42
|
+
if (!config2) {
|
|
43
|
+
console.log(
|
|
44
|
+
`No AI config set. Choose a default model: ${configureCommandName} ${formatConfigureProviders()}`
|
|
45
|
+
);
|
|
46
|
+
console.log(
|
|
47
|
+
"Provider credentials still come from your shell or .env file."
|
|
48
|
+
);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
printAiConfig(config2, configPath);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
if (input.clear) {
|
|
55
|
+
const removed = clearAiConfig(configPath);
|
|
56
|
+
if (removed) {
|
|
57
|
+
console.log(`Cleared AI config: ${configPath}`);
|
|
58
|
+
} else {
|
|
59
|
+
console.log("No AI config was set.");
|
|
60
|
+
}
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const model = resolveModelFromInput(presetArg);
|
|
64
|
+
if (!model) {
|
|
65
|
+
console.log(
|
|
66
|
+
`Usage: ${configureCommandName} <${CONFIGURE_PROVIDERS.join("|")}|provider/model-id>
|
|
67
|
+
${configureCommandName}
|
|
68
|
+
${configureCommandName} --clear`
|
|
69
|
+
);
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid provider or model. Use one of: ${formatConfigureProviders()}, or a full model string like "openai/gpt-4o".`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const config = writeAiConfig(model, configPath);
|
|
75
|
+
console.log("AI config saved.");
|
|
76
|
+
printAiConfig(config, configPath);
|
|
77
|
+
}
|
|
4
78
|
const aiConfigureInput = SimpleCLI.input({
|
|
5
79
|
positionals: [
|
|
6
80
|
SimpleCLI.positional("preset", z.string().optional(), {
|
|
@@ -31,5 +105,6 @@ const aiCommands = SimpleCLI.group({
|
|
|
31
105
|
});
|
|
32
106
|
export {
|
|
33
107
|
aiCommands,
|
|
34
|
-
aiConfigureInput
|
|
108
|
+
aiConfigureInput,
|
|
109
|
+
runAiConfigure
|
|
35
110
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { SessionAccessModeSchema } from "../../shared/state/index.js";
|
|
2
3
|
import {
|
|
3
4
|
runClose as runCloseWithLogger,
|
|
4
5
|
runCloseAll as runCloseAllWithLogger,
|
|
@@ -7,11 +8,14 @@ import {
|
|
|
7
8
|
runPages,
|
|
8
9
|
runSave
|
|
9
10
|
} from "../core/browser.js";
|
|
11
|
+
import { readLibrettoConfig } from "../core/config.js";
|
|
10
12
|
import { createLoggerForSession, withSessionLogger } from "../core/context.js";
|
|
11
13
|
import {
|
|
12
14
|
assertSessionAvailableForStart,
|
|
15
|
+
setSessionMode,
|
|
13
16
|
validateSessionName
|
|
14
17
|
} from "../core/session.js";
|
|
18
|
+
import { warnIfInstalledSkillOutOfDate } from "../core/skill-version.js";
|
|
15
19
|
import { SimpleCLI } from "../framework/simple-cli.js";
|
|
16
20
|
import {
|
|
17
21
|
sessionOption,
|
|
@@ -35,6 +39,12 @@ function parseViewportArg(viewportArg) {
|
|
|
35
39
|
}
|
|
36
40
|
return { width, height };
|
|
37
41
|
}
|
|
42
|
+
function resolveRequestedSessionMode(readOnly, writeAccess) {
|
|
43
|
+
if (readOnly) return "read-only";
|
|
44
|
+
if (writeAccess) return "write-access";
|
|
45
|
+
const config = readLibrettoConfig();
|
|
46
|
+
return config.sessionMode ?? "write-access";
|
|
47
|
+
}
|
|
38
48
|
const openInput = SimpleCLI.input({
|
|
39
49
|
positionals: [
|
|
40
50
|
SimpleCLI.positional("url", z.string().optional(), {
|
|
@@ -45,24 +55,39 @@ const openInput = SimpleCLI.input({
|
|
|
45
55
|
session: sessionOption(),
|
|
46
56
|
headed: SimpleCLI.flag({ help: "Run browser in headed mode" }),
|
|
47
57
|
headless: SimpleCLI.flag({ help: "Run browser in headless mode" }),
|
|
58
|
+
readOnly: SimpleCLI.flag({
|
|
59
|
+
name: "read-only",
|
|
60
|
+
help: "Create the session in read-only mode"
|
|
61
|
+
}),
|
|
62
|
+
writeAccess: SimpleCLI.flag({
|
|
63
|
+
name: "write-access",
|
|
64
|
+
help: "Create the session in write-access mode (overrides config default)"
|
|
65
|
+
}),
|
|
48
66
|
viewport: SimpleCLI.option(z.string().optional(), {
|
|
49
67
|
help: "Viewport size as WIDTHxHEIGHT (e.g. 1920x1080)"
|
|
50
68
|
})
|
|
51
69
|
}
|
|
52
70
|
}).refine(
|
|
53
71
|
(input) => Boolean(input.url),
|
|
54
|
-
`Usage: libretto open <url> [--headless] [--viewport WxH] [--session <name>]`
|
|
72
|
+
`Usage: libretto open <url> [--headless] [--read-only|--write-access] [--viewport WxH] [--session <name>]`
|
|
55
73
|
).refine(
|
|
56
74
|
(input) => !(input.headed && input.headless),
|
|
57
75
|
"Cannot pass both --headed and --headless."
|
|
76
|
+
).refine(
|
|
77
|
+
(input) => !(input.readOnly && input.writeAccess),
|
|
78
|
+
"Cannot pass both --read-only and --write-access."
|
|
58
79
|
);
|
|
59
80
|
const openCommand = SimpleCLI.command({
|
|
60
81
|
description: "Launch browser and open URL (headed by default)"
|
|
61
82
|
}).input(openInput).use(withAutoSession()).handle(async ({ input, ctx }) => {
|
|
83
|
+
warnIfInstalledSkillOutOfDate();
|
|
62
84
|
assertSessionAvailableForStart(ctx.session, ctx.logger);
|
|
63
85
|
const headed = input.headed || !input.headless;
|
|
64
86
|
const viewport = parseViewportArg(input.viewport);
|
|
65
|
-
await runOpen(input.url, headed, ctx.session, ctx.logger, {
|
|
87
|
+
await runOpen(input.url, headed, ctx.session, ctx.logger, {
|
|
88
|
+
viewport,
|
|
89
|
+
accessMode: resolveRequestedSessionMode(input.readOnly, input.writeAccess)
|
|
90
|
+
});
|
|
66
91
|
});
|
|
67
92
|
const connectInput = SimpleCLI.input({
|
|
68
93
|
positionals: [
|
|
@@ -71,16 +96,33 @@ const connectInput = SimpleCLI.input({
|
|
|
71
96
|
})
|
|
72
97
|
],
|
|
73
98
|
named: {
|
|
74
|
-
session: sessionOption()
|
|
99
|
+
session: sessionOption(),
|
|
100
|
+
readOnly: SimpleCLI.flag({
|
|
101
|
+
name: "read-only",
|
|
102
|
+
help: "Create the session in read-only mode"
|
|
103
|
+
}),
|
|
104
|
+
writeAccess: SimpleCLI.flag({
|
|
105
|
+
name: "write-access",
|
|
106
|
+
help: "Create the session in write-access mode (overrides config default)"
|
|
107
|
+
})
|
|
75
108
|
}
|
|
76
109
|
}).refine(
|
|
77
110
|
(input) => Boolean(input.cdpUrl),
|
|
78
|
-
`Usage: libretto connect <cdp-url> --session <name>`
|
|
111
|
+
`Usage: libretto connect <cdp-url> [--read-only|--write-access] --session <name>`
|
|
112
|
+
).refine(
|
|
113
|
+
(input) => !(input.readOnly && input.writeAccess),
|
|
114
|
+
"Cannot pass both --read-only and --write-access."
|
|
79
115
|
);
|
|
80
116
|
const connectCommand = SimpleCLI.command({
|
|
81
117
|
description: "Connect to an existing Chrome DevTools Protocol (CDP) endpoint"
|
|
82
118
|
}).input(connectInput).use(withAutoSession()).handle(async ({ input, ctx }) => {
|
|
83
|
-
|
|
119
|
+
warnIfInstalledSkillOutOfDate();
|
|
120
|
+
await runConnectWithLogger(
|
|
121
|
+
input.cdpUrl,
|
|
122
|
+
ctx.session,
|
|
123
|
+
ctx.logger,
|
|
124
|
+
resolveRequestedSessionMode(input.readOnly, input.writeAccess)
|
|
125
|
+
);
|
|
84
126
|
});
|
|
85
127
|
const saveInput = SimpleCLI.input({
|
|
86
128
|
positionals: [
|
|
@@ -111,6 +153,26 @@ const pagesCommand = SimpleCLI.command({
|
|
|
111
153
|
}).input(pagesInput).use(withRequiredSession()).handle(async ({ ctx }) => {
|
|
112
154
|
await runPages(ctx.session, ctx.logger);
|
|
113
155
|
});
|
|
156
|
+
const sessionModeInput = SimpleCLI.input({
|
|
157
|
+
positionals: [
|
|
158
|
+
SimpleCLI.positional("mode", SessionAccessModeSchema.optional(), {
|
|
159
|
+
help: "Session mode to set"
|
|
160
|
+
})
|
|
161
|
+
],
|
|
162
|
+
named: {
|
|
163
|
+
session: sessionOption()
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
const sessionModeCommand = SimpleCLI.command({
|
|
167
|
+
description: "View or set the session access mode"
|
|
168
|
+
}).input(sessionModeInput).use(withRequiredSession()).handle(async ({ input, ctx }) => {
|
|
169
|
+
if (!input.mode) {
|
|
170
|
+
console.log(`Session "${ctx.session}" mode: ${ctx.sessionState.mode}`);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const nextState = setSessionMode(ctx.session, input.mode, ctx.logger);
|
|
174
|
+
console.log(`Session "${ctx.session}" mode set to ${nextState.mode}.`);
|
|
175
|
+
});
|
|
114
176
|
const closeInput = SimpleCLI.input({
|
|
115
177
|
positionals: [],
|
|
116
178
|
named: {
|
|
@@ -147,6 +209,7 @@ const browserCommands = {
|
|
|
147
209
|
connect: connectCommand,
|
|
148
210
|
save: saveCommand,
|
|
149
211
|
pages: pagesCommand,
|
|
212
|
+
"session-mode": sessionModeCommand,
|
|
150
213
|
close: closeCommand
|
|
151
214
|
};
|
|
152
215
|
async function runClose(session) {
|
|
@@ -167,5 +230,7 @@ export {
|
|
|
167
230
|
parseViewportArg,
|
|
168
231
|
runClose,
|
|
169
232
|
saveCommand,
|
|
170
|
-
saveInput
|
|
233
|
+
saveInput,
|
|
234
|
+
sessionModeCommand,
|
|
235
|
+
sessionModeInput
|
|
171
236
|
};
|