libretto 0.6.18 → 0.6.20
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 +10 -13
- package/README.template.md +10 -13
- package/dist/cli/cli.js +2 -16
- package/dist/cli/commands/browser.js +3 -3
- package/dist/cli/commands/deploy.js +5 -0
- package/dist/cli/commands/execution.js +2 -2
- package/dist/cli/commands/update.js +47 -18
- package/dist/cli/core/daemon/daemon.js +2 -0
- package/dist/cli/core/skill-version.js +49 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -0
- package/dist/shared/workflow/workflow.d.ts +6 -1
- package/dist/shared/workflow/workflow.js +13 -10
- package/docs/releasing.md +6 -4
- package/package.json +1 -1
- package/skills/libretto/SKILL.md +36 -35
- package/skills/libretto/references/auth-profiles.md +3 -3
- package/skills/libretto/references/code-generation-rules.md +2 -2
- package/skills/libretto/references/configuration-file-reference.md +10 -10
- package/skills/libretto/references/pages-and-page-targeting.md +3 -3
- package/skills/libretto-readonly/SKILL.md +1 -1
- package/src/cli/cli.ts +2 -19
- package/src/cli/commands/browser.ts +3 -3
- package/src/cli/commands/deploy.ts +5 -0
- package/src/cli/commands/execution.ts +2 -2
- package/src/cli/commands/update.ts +57 -19
- package/src/cli/core/daemon/daemon.ts +2 -0
- package/src/cli/core/skill-version.ts +67 -17
- package/src/index.ts +2 -0
- package/src/shared/workflow/workflow.ts +27 -10
package/README.md
CHANGED
|
@@ -28,17 +28,14 @@ https://github.com/user-attachments/assets/9b9a0ab3-5133-4b20-b3be-459943349d18
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
#
|
|
32
|
-
curl -fsSL https://libretto.sh/install.sh | bash
|
|
33
|
-
|
|
34
|
-
# Add Libretto to your project
|
|
31
|
+
# Add Libretto to your project. Requires Node.js and npm.
|
|
35
32
|
npm install libretto
|
|
36
33
|
|
|
37
34
|
# First-time onboarding: install skills and download Chromium
|
|
38
|
-
libretto setup
|
|
35
|
+
npx libretto setup
|
|
39
36
|
|
|
40
37
|
# Check workspace readiness at any time
|
|
41
|
-
libretto status
|
|
38
|
+
npx libretto status
|
|
42
39
|
```
|
|
43
40
|
|
|
44
41
|
`setup` creates the `.libretto/` directory, installs agent skills, and downloads Chromium unless you pass `--skip-browsers`.
|
|
@@ -76,17 +73,17 @@ Agents can use Libretto to reproduce the failure, pause the workflow at any poin
|
|
|
76
73
|
You can also use Libretto directly from the command line. All commands accept `--session <name>` to target a specific session.
|
|
77
74
|
|
|
78
75
|
```bash
|
|
79
|
-
libretto open <url> # launch browser and open a URL
|
|
80
|
-
libretto run ./integration.ts --headless # run a workflow and close on success
|
|
81
|
-
libretto run ./integration.ts --headless --stay-open-on-success # keep a successful run inspectable
|
|
82
|
-
libretto snapshot --session <name> # capture a screenshot and compact accessibility tree
|
|
83
|
-
libretto exec "<code>" # execute Playwright TypeScript against the open page
|
|
84
|
-
libretto close # close the browser
|
|
76
|
+
npx libretto open <url> # launch browser and open a URL
|
|
77
|
+
npx libretto run ./integration.ts --headless # run a workflow and close on success
|
|
78
|
+
npx libretto run ./integration.ts --headless --stay-open-on-success # keep a successful run inspectable
|
|
79
|
+
npx libretto snapshot --session <name> # capture a screenshot and compact accessibility tree
|
|
80
|
+
npx libretto exec "<code>" # execute Playwright TypeScript against the open page
|
|
81
|
+
npx libretto close # close the browser
|
|
85
82
|
```
|
|
86
83
|
|
|
87
84
|
`run` sessions are inspectable through the same daemon-backed commands as `open` sessions. Successful runs close the browser by default; pass `--stay-open-on-success` to keep the browser open for `pages`, `snapshot`, and `exec`. Failed or paused workflows keep the browser open so you can inspect the exact page state before fixing or resuming the workflow.
|
|
88
85
|
|
|
89
|
-
Run `libretto help` for the full list of commands.
|
|
86
|
+
Run `npx libretto help` for the full list of commands.
|
|
90
87
|
|
|
91
88
|
## Configuration
|
|
92
89
|
|
package/README.template.md
CHANGED
|
@@ -26,17 +26,14 @@ https://github.com/user-attachments/assets/9b9a0ab3-5133-4b20-b3be-459943349d18
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
#
|
|
30
|
-
curl -fsSL https://libretto.sh/install.sh | bash
|
|
31
|
-
|
|
32
|
-
# Add Libretto to your project
|
|
29
|
+
# Add Libretto to your project. Requires Node.js and npm.
|
|
33
30
|
npm install libretto
|
|
34
31
|
|
|
35
32
|
# First-time onboarding: install skills and download Chromium
|
|
36
|
-
libretto setup
|
|
33
|
+
npx libretto setup
|
|
37
34
|
|
|
38
35
|
# Check workspace readiness at any time
|
|
39
|
-
libretto status
|
|
36
|
+
npx libretto status
|
|
40
37
|
```
|
|
41
38
|
|
|
42
39
|
`setup` creates the `.libretto/` directory, installs agent skills, and downloads Chromium unless you pass `--skip-browsers`.
|
|
@@ -74,17 +71,17 @@ Agents can use Libretto to reproduce the failure, pause the workflow at any poin
|
|
|
74
71
|
You can also use Libretto directly from the command line. All commands accept `--session <name>` to target a specific session.
|
|
75
72
|
|
|
76
73
|
```bash
|
|
77
|
-
libretto open <url> # launch browser and open a URL
|
|
78
|
-
libretto run ./integration.ts --headless # run a workflow and close on success
|
|
79
|
-
libretto run ./integration.ts --headless --stay-open-on-success # keep a successful run inspectable
|
|
80
|
-
libretto snapshot --session <name> # capture a screenshot and compact accessibility tree
|
|
81
|
-
libretto exec "<code>" # execute Playwright TypeScript against the open page
|
|
82
|
-
libretto close # close the browser
|
|
74
|
+
npx libretto open <url> # launch browser and open a URL
|
|
75
|
+
npx libretto run ./integration.ts --headless # run a workflow and close on success
|
|
76
|
+
npx libretto run ./integration.ts --headless --stay-open-on-success # keep a successful run inspectable
|
|
77
|
+
npx libretto snapshot --session <name> # capture a screenshot and compact accessibility tree
|
|
78
|
+
npx libretto exec "<code>" # execute Playwright TypeScript against the open page
|
|
79
|
+
npx libretto close # close the browser
|
|
83
80
|
```
|
|
84
81
|
|
|
85
82
|
`run` sessions are inspectable through the same daemon-backed commands as `open` sessions. Successful runs close the browser by default; pass `--stay-open-on-success` to keep the browser open for `pages`, `snapshot`, and `exec`. Failed or paused workflows keep the browser open so you can inspect the exact page state before fixing or resuming the workflow.
|
|
86
83
|
|
|
87
|
-
Run `libretto help` for the full list of commands.
|
|
84
|
+
Run `npx libretto help` for the full list of commands.
|
|
88
85
|
|
|
89
86
|
## Configuration
|
|
90
87
|
|
package/dist/cli/cli.js
CHANGED
|
@@ -2,27 +2,14 @@ import { ensureLibrettoSetup } from "./core/context.js";
|
|
|
2
2
|
import { createCLIApp } from "./router.js";
|
|
3
3
|
import {
|
|
4
4
|
readCurrentCliVersion,
|
|
5
|
-
|
|
5
|
+
warnIfLibrettoVersionsDiffer
|
|
6
6
|
} from "./core/skill-version.js";
|
|
7
7
|
import { loadEnv } from "../shared/env/load-env.js";
|
|
8
8
|
function renderVersion() {
|
|
9
9
|
return readCurrentCliVersion();
|
|
10
10
|
}
|
|
11
11
|
function printSetupAudit() {
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
function isPackageManagerExec(env = process.env) {
|
|
15
|
-
return env.npm_command === "exec";
|
|
16
|
-
}
|
|
17
|
-
function warnIfPackageManagerExec() {
|
|
18
|
-
if (!isPackageManagerExec()) return;
|
|
19
|
-
console.error(
|
|
20
|
-
[
|
|
21
|
-
"Warning: running Libretto through a package manager is deprecated and will be removed in a future release.",
|
|
22
|
-
"Install the native command instead:",
|
|
23
|
-
" curl -fsSL https://libretto.sh/install.sh | bash"
|
|
24
|
-
].join("\n")
|
|
25
|
-
);
|
|
12
|
+
warnIfLibrettoVersionsDiffer();
|
|
26
13
|
}
|
|
27
14
|
function isRootHelpRequest(rawArgs) {
|
|
28
15
|
if (rawArgs.length === 0) return true;
|
|
@@ -42,7 +29,6 @@ async function runLibrettoCLI() {
|
|
|
42
29
|
const rawArgs = process.argv.slice(2);
|
|
43
30
|
let exitCode = 0;
|
|
44
31
|
loadEnv();
|
|
45
|
-
warnIfPackageManagerExec();
|
|
46
32
|
ensureLibrettoSetup();
|
|
47
33
|
const app = createCLIApp();
|
|
48
34
|
try {
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
setSessionMode,
|
|
18
18
|
validateSessionName
|
|
19
19
|
} from "../core/session.js";
|
|
20
|
-
import {
|
|
20
|
+
import { warnIfLibrettoVersionsDiffer } from "../core/skill-version.js";
|
|
21
21
|
import { SimpleCLI } from "affordance";
|
|
22
22
|
import {
|
|
23
23
|
sessionOption,
|
|
@@ -88,7 +88,7 @@ const openInput = SimpleCLI.input({
|
|
|
88
88
|
const openCommand = SimpleCLI.command({
|
|
89
89
|
description: "Launch browser and open URL"
|
|
90
90
|
}).input(openInput).use(withAutoSession()).use(withExperiments()).handle(async ({ input, ctx }) => {
|
|
91
|
-
|
|
91
|
+
warnIfLibrettoVersionsDiffer();
|
|
92
92
|
assertSessionAvailableForStart(ctx.session, ctx.logger);
|
|
93
93
|
const providerName = resolveProviderName(input.provider);
|
|
94
94
|
if (providerName === "local") {
|
|
@@ -141,7 +141,7 @@ const connectInput = SimpleCLI.input({
|
|
|
141
141
|
const connectCommand = SimpleCLI.command({
|
|
142
142
|
description: "Connect to an existing Chrome DevTools Protocol (CDP) endpoint"
|
|
143
143
|
}).input(connectInput).use(withAutoSession()).use(withExperiments()).handle(async ({ input, ctx }) => {
|
|
144
|
-
|
|
144
|
+
warnIfLibrettoVersionsDiffer();
|
|
145
145
|
await runConnectWithLogger(
|
|
146
146
|
input.cdpUrl,
|
|
147
147
|
ctx.session,
|
|
@@ -93,6 +93,10 @@ const deployInput = SimpleCLI.input({
|
|
|
93
93
|
name: "entry-point",
|
|
94
94
|
help: "Entry point file (default: index.ts)"
|
|
95
95
|
}),
|
|
96
|
+
autoRepair: SimpleCLI.flag({
|
|
97
|
+
name: "auto-repair",
|
|
98
|
+
help: "Route failed jobs for this deployment to autofix"
|
|
99
|
+
}),
|
|
96
100
|
external: SimpleCLI.option(
|
|
97
101
|
z.string().optional().transform(
|
|
98
102
|
(value) => value?.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0) ?? []
|
|
@@ -120,6 +124,7 @@ const deployCommand = SimpleCLI.command({
|
|
|
120
124
|
entry_point: entryPoint
|
|
121
125
|
};
|
|
122
126
|
if (input.description) createPayload.description = input.description;
|
|
127
|
+
if (input.autoRepair) createPayload.auto_repair = true;
|
|
123
128
|
console.log("Uploading deployment...");
|
|
124
129
|
const body = await orpcCall({
|
|
125
130
|
apiUrl,
|
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
setSessionStatus,
|
|
24
24
|
writeSessionState
|
|
25
25
|
} from "../core/session.js";
|
|
26
|
-
import {
|
|
26
|
+
import { warnIfLibrettoVersionsDiffer } from "../core/skill-version.js";
|
|
27
27
|
import { readLibrettoConfig } from "../core/config.js";
|
|
28
28
|
import { renderSnapshotDiff } from "../../shared/snapshot/diff-snapshots.js";
|
|
29
29
|
import {
|
|
@@ -682,7 +682,7 @@ function resolveRunParams(rawInlineParams, paramsFile) {
|
|
|
682
682
|
const runCommand = SimpleCLI.command({
|
|
683
683
|
description: "Run the default-exported Libretto workflow from a file"
|
|
684
684
|
}).input(runInput).use(withAutoSession()).use(withExperiments()).handle(async ({ input, ctx }) => {
|
|
685
|
-
|
|
685
|
+
warnIfLibrettoVersionsDiffer();
|
|
686
686
|
await stopExistingFailedRunSession(ctx.session, ctx.logger);
|
|
687
687
|
assertSessionAvailableForStart(ctx.session, ctx.logger);
|
|
688
688
|
const params = resolveRunParams(input.params, input.paramsFile);
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
import { SimpleCLI } from "affordance";
|
|
5
|
-
|
|
6
|
+
import { REPO_ROOT } from "../core/context.js";
|
|
7
|
+
import {
|
|
8
|
+
detectProjectPackageManager,
|
|
9
|
+
installCommand
|
|
10
|
+
} from "../../shared/package-manager.js";
|
|
11
|
+
function packageInstallCommand(packageManager, packageSpec) {
|
|
12
|
+
return `${installCommand(packageManager)} ${packageSpec}`;
|
|
13
|
+
}
|
|
6
14
|
function readCurrentCliVersion() {
|
|
7
15
|
const packageJsonPath = fileURLToPath(
|
|
8
16
|
new URL("../../../package.json", import.meta.url)
|
|
@@ -17,6 +25,21 @@ function readCurrentCliVersion() {
|
|
|
17
25
|
}
|
|
18
26
|
return manifest.version;
|
|
19
27
|
}
|
|
28
|
+
function readPackageVersion(packageJsonPath) {
|
|
29
|
+
try {
|
|
30
|
+
const manifest = JSON.parse(
|
|
31
|
+
readFileSync(packageJsonPath, "utf8")
|
|
32
|
+
);
|
|
33
|
+
return manifest.version?.trim() || null;
|
|
34
|
+
} catch {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function readLocalPackageVersion() {
|
|
39
|
+
return readPackageVersion(
|
|
40
|
+
join(REPO_ROOT, "node_modules", "libretto", "package.json")
|
|
41
|
+
);
|
|
42
|
+
}
|
|
20
43
|
function readLatestNpmVersion() {
|
|
21
44
|
const result = spawnSync("npm", ["view", "libretto@latest", "version"], {
|
|
22
45
|
encoding: "utf8"
|
|
@@ -65,55 +88,61 @@ const updateInput = SimpleCLI.input({
|
|
|
65
88
|
})
|
|
66
89
|
}
|
|
67
90
|
});
|
|
68
|
-
function formatUpdateFailure(status, signal) {
|
|
69
|
-
const knownState = status === null ? `
|
|
91
|
+
function formatUpdateFailure(status, signal, updateCommand2) {
|
|
92
|
+
const knownState = status === null ? `package update was interrupted${signal ? ` by ${signal}` : ""}.` : `package update exited with status ${status}.`;
|
|
70
93
|
return [
|
|
71
94
|
"Error: failed to update Libretto to the latest version.",
|
|
72
95
|
`Known state: ${knownState}`,
|
|
73
|
-
`Try: ${
|
|
96
|
+
`Try: ${updateCommand2}`,
|
|
74
97
|
"Help: libretto help update"
|
|
75
98
|
].join("\n");
|
|
76
99
|
}
|
|
77
100
|
const updateCommand = SimpleCLI.command({
|
|
78
101
|
description: "Update Libretto to the latest version"
|
|
79
102
|
}).input(updateInput).handle(async ({ input }) => {
|
|
103
|
+
const packageManager = detectProjectPackageManager();
|
|
104
|
+
const updateCommand2 = packageInstallCommand(packageManager, "libretto@latest");
|
|
80
105
|
if (input.dryRun) {
|
|
81
106
|
console.log("Update command:");
|
|
82
|
-
console.log(` ${
|
|
107
|
+
console.log(` ${updateCommand2}`);
|
|
83
108
|
console.log("No changes made.");
|
|
84
109
|
return;
|
|
85
110
|
}
|
|
86
111
|
const currentVersion = readCurrentCliVersion();
|
|
112
|
+
const localPackageVersion = readLocalPackageVersion();
|
|
113
|
+
const installedVersion = localPackageVersion ?? currentVersion;
|
|
87
114
|
const latestVersion = readLatestNpmVersion();
|
|
88
|
-
console.log(`Current version: ${
|
|
115
|
+
console.log(`Current version: ${installedVersion}`);
|
|
89
116
|
console.log(`Latest version: ${latestVersion}`);
|
|
90
|
-
if (
|
|
91
|
-
console.log(`Libretto is already up to date (${
|
|
117
|
+
if (localPackageVersion && installedVersion === latestVersion) {
|
|
118
|
+
console.log(`Libretto is already up to date (${installedVersion}).`);
|
|
92
119
|
console.log("No further action required.");
|
|
93
120
|
return;
|
|
94
121
|
}
|
|
95
|
-
|
|
96
|
-
|
|
122
|
+
if (!localPackageVersion) {
|
|
123
|
+
console.log("Local package: not installed");
|
|
124
|
+
}
|
|
125
|
+
console.log("Updating local Libretto package to latest...");
|
|
126
|
+
const result = spawnSync(updateCommand2, {
|
|
97
127
|
stdio: "inherit",
|
|
98
|
-
|
|
99
|
-
...process.env,
|
|
100
|
-
LIBRETTO_VERSION: "latest"
|
|
101
|
-
}
|
|
128
|
+
shell: true
|
|
102
129
|
});
|
|
103
130
|
if (result.error) {
|
|
104
131
|
throw new Error(
|
|
105
132
|
[
|
|
106
|
-
"Error: failed to start the Libretto
|
|
133
|
+
"Error: failed to start the Libretto package update.",
|
|
107
134
|
`Known state: ${result.error.message}`,
|
|
108
|
-
`Try: ${
|
|
135
|
+
`Try: ${updateCommand2}`,
|
|
109
136
|
"Help: libretto help update"
|
|
110
137
|
].join("\n")
|
|
111
138
|
);
|
|
112
139
|
}
|
|
113
140
|
if (result.status !== 0) {
|
|
114
|
-
throw new Error(
|
|
141
|
+
throw new Error(
|
|
142
|
+
formatUpdateFailure(result.status, result.signal, updateCommand2)
|
|
143
|
+
);
|
|
115
144
|
}
|
|
116
|
-
console.log("Libretto updated to latest.");
|
|
145
|
+
console.log("Local Libretto package updated to latest.");
|
|
117
146
|
console.log("No further action required.");
|
|
118
147
|
});
|
|
119
148
|
export {
|
|
@@ -47,6 +47,7 @@ import {
|
|
|
47
47
|
loadDefaultWorkflow
|
|
48
48
|
} from "../workflow-runtime.js";
|
|
49
49
|
import { WorkflowController } from "../workflow-runner/runner.js";
|
|
50
|
+
import { validateWorkflowInput } from "../../../shared/workflow/workflow.js";
|
|
50
51
|
function isOperationalPage(page) {
|
|
51
52
|
const url = page.url();
|
|
52
53
|
return !url.startsWith("devtools://") && !url.startsWith("chrome-error://");
|
|
@@ -682,6 +683,7 @@ async function main() {
|
|
|
682
683
|
loadedWorkflow = await loadDefaultWorkflow(
|
|
683
684
|
getAbsoluteIntegrationPath(config.workflow.integrationPath)
|
|
684
685
|
);
|
|
686
|
+
validateWorkflowInput(loadedWorkflow, config.workflow.params ?? {});
|
|
685
687
|
} catch (error) {
|
|
686
688
|
throw new UserFacingStartupError(
|
|
687
689
|
error instanceof Error ? error.message : String(error)
|
|
@@ -7,6 +7,15 @@ const INSTALLED_SKILL_PATHS = [
|
|
|
7
7
|
[".claude", "skills", "libretto", "SKILL.md"]
|
|
8
8
|
];
|
|
9
9
|
let cachedCliVersion = null;
|
|
10
|
+
function readPackageVersion(packageJsonPath) {
|
|
11
|
+
if (!existsSync(packageJsonPath)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const manifest = JSON.parse(
|
|
15
|
+
readFileSync(packageJsonPath, "utf8")
|
|
16
|
+
);
|
|
17
|
+
return manifest.version?.trim() || null;
|
|
18
|
+
}
|
|
10
19
|
function readCurrentCliVersion() {
|
|
11
20
|
if (cachedCliVersion) {
|
|
12
21
|
return cachedCliVersion;
|
|
@@ -14,17 +23,20 @@ function readCurrentCliVersion() {
|
|
|
14
23
|
const packageJsonPath = fileURLToPath(
|
|
15
24
|
new URL("../../../package.json", import.meta.url)
|
|
16
25
|
);
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
);
|
|
20
|
-
if (!manifest.version) {
|
|
26
|
+
const version = readPackageVersion(packageJsonPath);
|
|
27
|
+
if (!version) {
|
|
21
28
|
throw new Error(
|
|
22
29
|
`Unable to determine current libretto version from ${packageJsonPath}.`
|
|
23
30
|
);
|
|
24
31
|
}
|
|
25
|
-
cachedCliVersion =
|
|
32
|
+
cachedCliVersion = version;
|
|
26
33
|
return cachedCliVersion;
|
|
27
34
|
}
|
|
35
|
+
function readLocalPackageVersion() {
|
|
36
|
+
return readPackageVersion(
|
|
37
|
+
join(REPO_ROOT, "node_modules", "libretto", "package.json")
|
|
38
|
+
);
|
|
39
|
+
}
|
|
28
40
|
function readInstalledSkillVersion(skillPath) {
|
|
29
41
|
if (!existsSync(skillPath)) {
|
|
30
42
|
return null;
|
|
@@ -45,30 +57,52 @@ function readInstalledSkillVersion(skillPath) {
|
|
|
45
57
|
);
|
|
46
58
|
return versionMatch?.[1]?.trim() ?? null;
|
|
47
59
|
}
|
|
48
|
-
function
|
|
49
|
-
const
|
|
60
|
+
function readInstalledSkillVersions() {
|
|
61
|
+
const versions = /* @__PURE__ */ new Set();
|
|
50
62
|
for (const relativePathParts of INSTALLED_SKILL_PATHS) {
|
|
51
63
|
const skillPath = join(REPO_ROOT, ...relativePathParts);
|
|
52
64
|
const installedVersion = readInstalledSkillVersion(skillPath);
|
|
53
|
-
if (installedVersion
|
|
54
|
-
|
|
65
|
+
if (installedVersion) {
|
|
66
|
+
versions.add(installedVersion);
|
|
55
67
|
}
|
|
56
68
|
}
|
|
57
|
-
return
|
|
69
|
+
return [...versions];
|
|
70
|
+
}
|
|
71
|
+
function formatSkillVersions(versions) {
|
|
72
|
+
if (versions.length === 0) {
|
|
73
|
+
return "not installed";
|
|
74
|
+
}
|
|
75
|
+
return versions.join(", ");
|
|
76
|
+
}
|
|
77
|
+
function formatVersionWarning(components) {
|
|
78
|
+
const skillLabel = components.skillVersions.length > 1 ? "agent skills" : "agent skill";
|
|
79
|
+
return [
|
|
80
|
+
"WARNING: Libretto skill version does not match the local package.",
|
|
81
|
+
` local package: ${components.localPackageVersion ?? `${components.cliVersion} (current command)`}`,
|
|
82
|
+
` ${skillLabel}: ${formatSkillVersions(components.skillVersions)}`,
|
|
83
|
+
"Fix: run libretto setup"
|
|
84
|
+
].join("\n");
|
|
58
85
|
}
|
|
59
|
-
function
|
|
86
|
+
function warnIfLibrettoVersionsDiffer() {
|
|
60
87
|
try {
|
|
61
|
-
const
|
|
62
|
-
|
|
88
|
+
const cliVersion = readCurrentCliVersion();
|
|
89
|
+
const localPackageVersion = readLocalPackageVersion();
|
|
90
|
+
const packageVersion = localPackageVersion ?? cliVersion;
|
|
91
|
+
const skillVersions = readInstalledSkillVersions();
|
|
92
|
+
if (skillVersions.length === 0 || skillVersions.every((skillVersion) => skillVersion === packageVersion)) {
|
|
63
93
|
return;
|
|
64
94
|
}
|
|
65
95
|
console.error(
|
|
66
|
-
|
|
96
|
+
formatVersionWarning({
|
|
97
|
+
cliVersion,
|
|
98
|
+
localPackageVersion,
|
|
99
|
+
skillVersions
|
|
100
|
+
})
|
|
67
101
|
);
|
|
68
102
|
} catch {
|
|
69
103
|
}
|
|
70
104
|
}
|
|
71
105
|
export {
|
|
72
106
|
readCurrentCliVersion,
|
|
73
|
-
|
|
107
|
+
warnIfLibrettoVersionsDiffer
|
|
74
108
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { InstrumentationOptions, InstrumentedPage, installInstrumentation, instr
|
|
|
12
12
|
export { GhostCursorOptions, ensureGhostCursor, ghostClick, hideGhostCursor, moveGhostCursor } from './shared/visualization/ghost-cursor.js';
|
|
13
13
|
export { HighlightOptions, clearHighlights, ensureHighlightLayer, showHighlight } from './shared/visualization/highlight.js';
|
|
14
14
|
export { BrowserSession, LaunchBrowserArgs, launchBrowser } from './shared/run/browser.js';
|
|
15
|
-
export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowInputError, LibrettoWorkflowSchemas, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, workflow } from './shared/workflow/workflow.js';
|
|
15
|
+
export { ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, LibrettoWorkflowContext, LibrettoWorkflowHandler, LibrettoWorkflowInputError, LibrettoWorkflowSchemas, WorkflowInputValidator, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, validateWorkflowInput, workflow } from './shared/workflow/workflow.js';
|
|
16
16
|
import 'zod';
|
|
17
17
|
import 'playwright';
|
|
18
18
|
import 'ai';
|
package/dist/index.js
CHANGED
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
LibrettoWorkflow,
|
|
60
60
|
LibrettoWorkflowInputError,
|
|
61
61
|
LIBRETTO_WORKFLOW_BRAND,
|
|
62
|
+
validateWorkflowInput,
|
|
62
63
|
workflow
|
|
63
64
|
} from "./shared/workflow/workflow.js";
|
|
64
65
|
const isDirectExecution = () => {
|
|
@@ -113,5 +114,6 @@ export {
|
|
|
113
114
|
prettyConsoleSink,
|
|
114
115
|
serializeSessionState,
|
|
115
116
|
showHighlight,
|
|
117
|
+
validateWorkflowInput,
|
|
116
118
|
workflow
|
|
117
119
|
};
|
|
@@ -16,6 +16,11 @@ declare class LibrettoWorkflowInputError extends Error {
|
|
|
16
16
|
readonly zodError: z.ZodError;
|
|
17
17
|
constructor(workflowName: string, zodError: z.ZodError);
|
|
18
18
|
}
|
|
19
|
+
type WorkflowInputValidator = {
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly inputSchema?: z.ZodType;
|
|
22
|
+
};
|
|
23
|
+
declare function validateWorkflowInput(workflow: WorkflowInputValidator, input: unknown): void;
|
|
19
24
|
declare class LibrettoWorkflow<InputSchema extends z.ZodType = z.ZodType<unknown>, OutputSchema extends z.ZodType = z.ZodType<unknown>> {
|
|
20
25
|
readonly [LIBRETTO_WORKFLOW_BRAND] = true;
|
|
21
26
|
readonly name: string;
|
|
@@ -40,4 +45,4 @@ declare function getWorkflowFromModuleExports(moduleExports: WorkflowModuleExpor
|
|
|
40
45
|
declare function workflow<InputSchema extends z.ZodType, OutputSchema extends z.ZodType>(name: string, schemas: LibrettoWorkflowSchemas<InputSchema, OutputSchema>, handler: LibrettoWorkflowHandler<z.infer<InputSchema>, z.infer<OutputSchema>>): LibrettoWorkflow<InputSchema, OutputSchema>;
|
|
41
46
|
declare function workflow<Input = unknown, Output = unknown>(name: string, handler: LibrettoWorkflowHandler<Input, Output>): LibrettoWorkflow<z.ZodType<Input>, z.ZodType<Output>>;
|
|
42
47
|
|
|
43
|
-
export { type ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, type LibrettoWorkflowContext, type LibrettoWorkflowHandler, LibrettoWorkflowInputError, type LibrettoWorkflowSchemas, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, workflow };
|
|
48
|
+
export { type ExportedLibrettoWorkflow, LIBRETTO_WORKFLOW_BRAND, LibrettoWorkflow, type LibrettoWorkflowContext, type LibrettoWorkflowHandler, LibrettoWorkflowInputError, type LibrettoWorkflowSchemas, type WorkflowInputValidator, getDefaultWorkflowFromModuleExports, getWorkflowFromModuleExports, getWorkflowsFromModuleExports, isLibrettoWorkflow, validateWorkflowInput, workflow };
|
|
@@ -19,6 +19,17 @@ function formatZodErrorMessage(workflowName, zodError) {
|
|
|
19
19
|
...lines
|
|
20
20
|
].join("\n");
|
|
21
21
|
}
|
|
22
|
+
function parseWorkflowInput(workflowName, inputSchema, input) {
|
|
23
|
+
if (!inputSchema) return input;
|
|
24
|
+
const result = inputSchema.safeParse(input);
|
|
25
|
+
if (!result.success) {
|
|
26
|
+
throw new LibrettoWorkflowInputError(workflowName, result.error);
|
|
27
|
+
}
|
|
28
|
+
return result.data;
|
|
29
|
+
}
|
|
30
|
+
function validateWorkflowInput(workflow2, input) {
|
|
31
|
+
parseWorkflowInput(workflow2.name, workflow2.inputSchema, input);
|
|
32
|
+
}
|
|
22
33
|
class LibrettoWorkflow {
|
|
23
34
|
[LIBRETTO_WORKFLOW_BRAND] = true;
|
|
24
35
|
name;
|
|
@@ -38,16 +49,7 @@ class LibrettoWorkflow {
|
|
|
38
49
|
this.handler = handler;
|
|
39
50
|
}
|
|
40
51
|
async run(ctx, input) {
|
|
41
|
-
|
|
42
|
-
if (this.inputSchema) {
|
|
43
|
-
const result = this.inputSchema.safeParse(input);
|
|
44
|
-
if (!result.success) {
|
|
45
|
-
throw new LibrettoWorkflowInputError(this.name, result.error);
|
|
46
|
-
}
|
|
47
|
-
parsed = result.data;
|
|
48
|
-
} else {
|
|
49
|
-
parsed = input;
|
|
50
|
-
}
|
|
52
|
+
const parsed = parseWorkflowInput(this.name, this.inputSchema, input);
|
|
51
53
|
return this.handler(ctx, parsed);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
@@ -118,5 +120,6 @@ export {
|
|
|
118
120
|
getWorkflowFromModuleExports,
|
|
119
121
|
getWorkflowsFromModuleExports,
|
|
120
122
|
isLibrettoWorkflow,
|
|
123
|
+
validateWorkflowInput,
|
|
121
124
|
workflow
|
|
122
125
|
};
|
package/docs/releasing.md
CHANGED
|
@@ -28,17 +28,19 @@ GitHub Actions needs these repository secrets:
|
|
|
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
|
|
|
31
|
-
On npm, configure
|
|
31
|
+
On npm, configure each published package to trust this repository and workflow for publishing:
|
|
32
32
|
|
|
33
33
|
- Organization or user: `saffron-health`
|
|
34
34
|
- Repository: `libretto`
|
|
35
35
|
- Workflow filename: `release.yml`
|
|
36
36
|
- Environment name: `release`
|
|
37
37
|
|
|
38
|
-
If you prefer the CLI,
|
|
38
|
+
If you prefer the CLI, run one setup command per package with npm 11.10.0 or newer:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
npm trust github libretto --repo saffron-health/libretto --file release.yml --env release
|
|
41
|
+
npx --yes npm@11.13.0 trust github libretto --repo saffron-health/libretto --file release.yml --env release --yes
|
|
42
|
+
npx --yes npm@11.13.0 trust github affordance --repo saffron-health/libretto --file release.yml --env release --yes
|
|
43
|
+
npx --yes npm@11.13.0 trust github create-libretto --repo saffron-health/libretto --file release.yml --env release --yes
|
|
42
44
|
```
|
|
43
45
|
|
|
44
46
|
Trusted publishing only works on supported cloud-hosted runners. This workflow uses `ubuntu-latest`, which satisfies that requirement. npm also requires a recent toolchain for trusted publishing, so the publish job runs on Node 24.
|
|
@@ -80,7 +82,7 @@ The workflow:
|
|
|
80
82
|
1. Reads the version from `packages/libretto/package.json`.
|
|
81
83
|
2. Checks whether that version already exists on npm and in GitHub Releases.
|
|
82
84
|
3. Runs install, type-check, and tests for the `libretto` package in a verification job.
|
|
83
|
-
4. Publishes `libretto@X.Y.Z
|
|
85
|
+
4. Publishes `affordance` first, then `libretto@X.Y.Z`, then `create-libretto@X.Y.Z` with trusted publishing.
|
|
84
86
|
5. Creates GitHub release `vX.Y.Z` with generated release notes if it does not already exist.
|
|
85
87
|
|
|
86
88
|
This makes the workflow safe to re-run after partial failures. For example, if npm publish succeeds but GitHub release creation fails, a re-run will skip npm and only create the missing release.
|