libretto 0.4.4 → 0.5.0
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/dist/cli/cli.js +20 -19
- package/dist/cli/commands/ai.js +1 -1
- package/dist/cli/commands/browser.js +3 -3
- package/dist/cli/commands/execution.js +3 -3
- package/dist/cli/commands/logs.js +1 -1
- package/dist/cli/core/browser.js +11 -6
- package/dist/cli/core/context.js +4 -18
- package/dist/cli/core/session.js +2 -2
- package/dist/cli/core/snapshot-analyzer.js +2 -2
- package/dist/cli/router.js +1 -1
- package/dist/cli/workers/run-integration-runtime.js +2 -2
- package/dist/shared/paths/paths.js +2 -1
- package/dist/shared/paths/repo-root.d.ts +3 -0
- package/dist/shared/paths/repo-root.js +24 -0
- package/package.json +6 -7
- package/scripts/postinstall.mjs +12 -3
- package/skills/libretto/SKILL.md +93 -404
- package/skills/libretto/references/auth-profiles.md +30 -0
- package/skills/libretto/references/pages-and-page-targeting.md +29 -0
- package/skills/libretto/references/reverse-engineering-network-requests.md +39 -0
- package/skills/libretto/references/user-action-log.md +31 -0
- package/src/cli/cli.ts +173 -0
- package/src/cli/commands/ai.ts +35 -0
- package/src/cli/commands/browser.ts +165 -0
- package/src/cli/commands/execution.ts +691 -0
- package/src/cli/commands/init.ts +327 -0
- package/src/cli/commands/logs.ts +128 -0
- package/src/cli/commands/shared.ts +70 -0
- package/src/cli/commands/snapshot.ts +327 -0
- package/src/cli/core/ai-config.ts +255 -0
- package/src/cli/core/api-snapshot-analyzer.ts +97 -0
- package/src/cli/core/browser.ts +839 -0
- package/src/cli/core/context.ts +122 -0
- package/src/cli/core/pause-signals.ts +35 -0
- package/src/cli/core/session-telemetry.ts +553 -0
- package/src/cli/core/session.ts +209 -0
- package/src/cli/core/snapshot-analyzer.ts +875 -0
- package/src/cli/core/snapshot-api-config.ts +236 -0
- package/src/cli/core/telemetry.ts +446 -0
- package/src/cli/framework/simple-cli.ts +1273 -0
- package/src/cli/index.ts +13 -0
- package/src/cli/router.ts +28 -0
- package/src/cli/workers/run-integration-runtime.ts +311 -0
- package/src/cli/workers/run-integration-worker-protocol.ts +14 -0
- package/src/cli/workers/run-integration-worker.ts +75 -0
- package/src/index.ts +120 -0
- package/src/runtime/download/download.ts +100 -0
- package/src/runtime/download/index.ts +7 -0
- package/src/runtime/extract/extract.ts +92 -0
- package/src/runtime/extract/index.ts +1 -0
- package/src/runtime/network/index.ts +5 -0
- package/src/runtime/network/network.ts +113 -0
- package/src/runtime/recovery/agent.ts +256 -0
- package/src/runtime/recovery/errors.ts +152 -0
- package/src/runtime/recovery/index.ts +7 -0
- package/src/runtime/recovery/recovery.ts +50 -0
- package/{dist/shared/condense-dom/condense-dom.cjs → src/shared/condense-dom/condense-dom.ts} +243 -115
- package/src/shared/config/config.ts +22 -0
- package/src/shared/config/index.ts +5 -0
- package/src/shared/debug/index.ts +1 -0
- package/src/shared/debug/pause.ts +85 -0
- package/src/shared/instrumentation/errors.ts +82 -0
- package/src/shared/instrumentation/index.ts +9 -0
- package/src/shared/instrumentation/instrument.ts +276 -0
- package/src/shared/llm/ai-sdk-adapter.ts +78 -0
- package/src/shared/llm/client.ts +217 -0
- package/src/shared/llm/index.ts +3 -0
- package/src/shared/llm/types.ts +63 -0
- package/src/shared/logger/index.ts +6 -0
- package/src/shared/logger/logger.ts +352 -0
- package/src/shared/logger/sinks.ts +144 -0
- package/src/shared/paths/paths.ts +109 -0
- package/src/shared/paths/repo-root.ts +27 -0
- package/src/shared/run/api.ts +2 -0
- package/src/shared/run/browser.ts +98 -0
- package/src/shared/state/index.ts +11 -0
- package/src/shared/state/session-state.ts +74 -0
- package/src/shared/visualization/ghost-cursor.ts +200 -0
- package/src/shared/visualization/highlight.ts +146 -0
- package/src/shared/visualization/index.ts +18 -0
- package/src/shared/workflow/workflow.ts +42 -0
- package/dist/index.cjs +0 -144
- package/dist/index.d.cts +0 -21
- package/dist/runtime/download/download.cjs +0 -70
- package/dist/runtime/download/download.d.cts +0 -35
- package/dist/runtime/download/index.cjs +0 -30
- package/dist/runtime/download/index.d.cts +0 -3
- package/dist/runtime/extract/extract.cjs +0 -88
- package/dist/runtime/extract/extract.d.cts +0 -23
- package/dist/runtime/extract/index.cjs +0 -28
- package/dist/runtime/extract/index.d.cts +0 -5
- package/dist/runtime/network/index.cjs +0 -28
- package/dist/runtime/network/index.d.cts +0 -4
- package/dist/runtime/network/network.cjs +0 -91
- package/dist/runtime/network/network.d.cts +0 -28
- package/dist/runtime/recovery/agent.cjs +0 -223
- package/dist/runtime/recovery/agent.d.cts +0 -13
- package/dist/runtime/recovery/errors.cjs +0 -124
- package/dist/runtime/recovery/errors.d.cts +0 -31
- package/dist/runtime/recovery/index.cjs +0 -34
- package/dist/runtime/recovery/index.d.cts +0 -7
- package/dist/runtime/recovery/recovery.cjs +0 -55
- package/dist/runtime/recovery/recovery.d.cts +0 -12
- package/dist/shared/condense-dom/condense-dom.d.cts +0 -34
- package/dist/shared/config/config.cjs +0 -44
- package/dist/shared/config/config.d.cts +0 -10
- package/dist/shared/config/index.cjs +0 -32
- package/dist/shared/config/index.d.cts +0 -1
- package/dist/shared/debug/index.cjs +0 -28
- package/dist/shared/debug/index.d.cts +0 -1
- package/dist/shared/debug/pause.cjs +0 -86
- package/dist/shared/debug/pause.d.cts +0 -12
- package/dist/shared/instrumentation/errors.cjs +0 -81
- package/dist/shared/instrumentation/errors.d.cts +0 -12
- package/dist/shared/instrumentation/index.cjs +0 -35
- package/dist/shared/instrumentation/index.d.cts +0 -6
- package/dist/shared/instrumentation/instrument.cjs +0 -206
- package/dist/shared/instrumentation/instrument.d.cts +0 -32
- package/dist/shared/llm/ai-sdk-adapter.cjs +0 -71
- package/dist/shared/llm/ai-sdk-adapter.d.cts +0 -22
- package/dist/shared/llm/client.cjs +0 -218
- package/dist/shared/llm/client.d.cts +0 -13
- package/dist/shared/llm/index.cjs +0 -31
- package/dist/shared/llm/index.d.cts +0 -5
- package/dist/shared/llm/types.cjs +0 -16
- package/dist/shared/llm/types.d.cts +0 -67
- package/dist/shared/logger/index.cjs +0 -37
- package/dist/shared/logger/index.d.cts +0 -2
- package/dist/shared/logger/logger.cjs +0 -232
- package/dist/shared/logger/logger.d.cts +0 -86
- package/dist/shared/logger/sinks.cjs +0 -160
- package/dist/shared/logger/sinks.d.cts +0 -9
- package/dist/shared/paths/paths.cjs +0 -104
- package/dist/shared/paths/paths.d.cts +0 -10
- package/dist/shared/run/api.cjs +0 -28
- package/dist/shared/run/api.d.cts +0 -2
- package/dist/shared/run/browser.cjs +0 -98
- package/dist/shared/run/browser.d.cts +0 -22
- package/dist/shared/state/index.cjs +0 -38
- package/dist/shared/state/index.d.cts +0 -2
- package/dist/shared/state/session-state.cjs +0 -92
- package/dist/shared/state/session-state.d.cts +0 -40
- package/dist/shared/visualization/ghost-cursor.cjs +0 -174
- package/dist/shared/visualization/ghost-cursor.d.cts +0 -37
- package/dist/shared/visualization/highlight.cjs +0 -134
- package/dist/shared/visualization/highlight.d.cts +0 -22
- package/dist/shared/visualization/index.cjs +0 -45
- package/dist/shared/visualization/index.d.cts +0 -3
- package/dist/shared/workflow/workflow.cjs +0 -47
- package/dist/shared/workflow/workflow.d.cts +0 -21
- package/skills/libretto/code-generation-rules.md +0 -223
- package/skills/libretto/integration-approach-selection.md +0 -174
package/dist/cli/cli.js
CHANGED
|
@@ -16,30 +16,30 @@ Options:
|
|
|
16
16
|
Built-in sessions: default, dev-server, browser-agent
|
|
17
17
|
|
|
18
18
|
Examples:
|
|
19
|
-
libretto
|
|
19
|
+
libretto open https://linkedin.com
|
|
20
20
|
|
|
21
21
|
# ... manually log in ...
|
|
22
|
-
libretto
|
|
22
|
+
libretto save linkedin.com
|
|
23
23
|
# Next time you open linkedin.com, you'll be logged in automatically
|
|
24
24
|
|
|
25
|
-
libretto
|
|
26
|
-
libretto
|
|
27
|
-
libretto
|
|
28
|
-
libretto
|
|
29
|
-
libretto
|
|
30
|
-
libretto
|
|
31
|
-
libretto
|
|
32
|
-
libretto
|
|
33
|
-
libretto
|
|
34
|
-
libretto
|
|
35
|
-
libretto
|
|
36
|
-
libretto
|
|
37
|
-
libretto
|
|
25
|
+
libretto exec "await page.locator('button:has-text(\\"Sign in\\")').click()"
|
|
26
|
+
libretto exec "await page.fill('input[name=\\"email\\"]', 'test@example.com')"
|
|
27
|
+
libretto ai configure openai
|
|
28
|
+
libretto ai configure anthropic
|
|
29
|
+
libretto ai configure gemini
|
|
30
|
+
libretto ai configure vertex
|
|
31
|
+
libretto ai configure openai/gpt-4o
|
|
32
|
+
libretto snapshot
|
|
33
|
+
libretto snapshot --objective "Find the submit button" --context "Submitting a referral form, already filled in patient details"
|
|
34
|
+
libretto resume --session default
|
|
35
|
+
libretto close
|
|
36
|
+
libretto close --all
|
|
37
|
+
libretto close --all --force
|
|
38
38
|
|
|
39
39
|
# Multiple sessions
|
|
40
|
-
libretto
|
|
41
|
-
libretto
|
|
42
|
-
libretto
|
|
40
|
+
libretto open https://site1.com --session test1
|
|
41
|
+
libretto open https://site2.com --session test2
|
|
42
|
+
libretto exec "return await page.title()" --session test1
|
|
43
43
|
|
|
44
44
|
Available in exec:
|
|
45
45
|
page, context, state, browser, networkLog, actionLog
|
|
@@ -93,7 +93,8 @@ function validateLegacySessionArg(rawArgs) {
|
|
|
93
93
|
if (value === void 0) return;
|
|
94
94
|
if (value === null) {
|
|
95
95
|
throw new Error(
|
|
96
|
-
|
|
96
|
+
`Usage: libretto <command> [--session <name>]
|
|
97
|
+
Missing or invalid --session value.`
|
|
97
98
|
);
|
|
98
99
|
}
|
|
99
100
|
validateSessionName(value);
|
package/dist/cli/commands/ai.js
CHANGED
|
@@ -47,7 +47,7 @@ const openInput = SimpleCLI.input({
|
|
|
47
47
|
}
|
|
48
48
|
}).refine(
|
|
49
49
|
(input) => Boolean(input.url),
|
|
50
|
-
|
|
50
|
+
`Usage: libretto open <url> [--headless] [--viewport WxH] [--session <name>]`
|
|
51
51
|
).refine(
|
|
52
52
|
(input) => !(input.headed && input.headless),
|
|
53
53
|
"Cannot pass both --headed and --headless."
|
|
@@ -73,7 +73,7 @@ const saveInput = SimpleCLI.input({
|
|
|
73
73
|
}
|
|
74
74
|
}).refine(
|
|
75
75
|
(input) => Boolean(input.urlOrDomain),
|
|
76
|
-
|
|
76
|
+
`Usage: libretto save <url|domain> [--session <name>]`
|
|
77
77
|
);
|
|
78
78
|
function createSaveCommand(logger) {
|
|
79
79
|
return SimpleCLI.command({
|
|
@@ -108,7 +108,7 @@ function createCloseCommand(logger) {
|
|
|
108
108
|
description: "Close the browser"
|
|
109
109
|
}).input(closeInput).use(resolveSessionMiddleware).handle(async ({ input, ctx }) => {
|
|
110
110
|
if (input.force && !input.all) {
|
|
111
|
-
throw new Error(
|
|
111
|
+
throw new Error(`Usage: libretto close --all [--force]`);
|
|
112
112
|
}
|
|
113
113
|
if (input.all) {
|
|
114
114
|
await runCloseAllWithLogger(logger, { force: input.force });
|
|
@@ -292,7 +292,7 @@ async function runResume(session, logger, sessionState) {
|
|
|
292
292
|
} = getPauseSignalPaths(session);
|
|
293
293
|
if (!existsSync(pausedSignalPath)) {
|
|
294
294
|
throw new Error(
|
|
295
|
-
`Session "${session}" is not paused. Run "libretto
|
|
295
|
+
`Session "${session}" is not paused. Run "libretto run ... --session ${session}" and call pause("${session}") first.`
|
|
296
296
|
);
|
|
297
297
|
}
|
|
298
298
|
if (!isProcessRunning(sessionState.pid)) {
|
|
@@ -414,7 +414,7 @@ const execInput = SimpleCLI.input({
|
|
|
414
414
|
}
|
|
415
415
|
}).refine(
|
|
416
416
|
(input) => input.codeParts.length > 0,
|
|
417
|
-
|
|
417
|
+
`Usage: libretto exec <code> [--session <name>] [--visualize]`
|
|
418
418
|
);
|
|
419
419
|
function createExecCommand(logger) {
|
|
420
420
|
return SimpleCLI.command({
|
|
@@ -429,7 +429,7 @@ function createExecCommand(logger) {
|
|
|
429
429
|
);
|
|
430
430
|
});
|
|
431
431
|
}
|
|
432
|
-
const runUsage =
|
|
432
|
+
const runUsage = `Usage: libretto run <integrationFile> <integrationExport> [--params <json> | --params-file <path>] [--tsconfig <path>] [--headed|--headless]`;
|
|
433
433
|
const runInput = SimpleCLI.input({
|
|
434
434
|
positionals: [
|
|
435
435
|
SimpleCLI.positional("integrationFile", z.string().optional(), {
|
|
@@ -26,7 +26,7 @@ async function resolvePageId(session, pageId) {
|
|
|
26
26
|
const foundPage = pages.find((page) => page.id === pageId);
|
|
27
27
|
if (!foundPage) {
|
|
28
28
|
throw new Error(
|
|
29
|
-
`Page "${pageId}" was not found in session "${session}". Run "libretto
|
|
29
|
+
`Page "${pageId}" was not found in session "${session}". Run "libretto pages --session ${session}" to list ids.`
|
|
30
30
|
);
|
|
31
31
|
}
|
|
32
32
|
return pageId;
|
package/dist/cli/core/browser.js
CHANGED
|
@@ -142,9 +142,14 @@ async function connect(session, logger, timeoutMs = 1e4, options) {
|
|
|
142
142
|
port: state.port,
|
|
143
143
|
pid: state.pid
|
|
144
144
|
});
|
|
145
|
-
|
|
145
|
+
if (!isPidRunning(state.pid)) {
|
|
146
|
+
clearSessionState(session, logger);
|
|
147
|
+
throw new Error(
|
|
148
|
+
`No browser running for session "${session}". Run 'libretto open <url> --session ${session}' first.`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
146
151
|
throw new Error(
|
|
147
|
-
`
|
|
152
|
+
`Could not connect to the browser for session "${session}" at http://127.0.0.1:${state.port}, but the session process (pid ${state.pid}) is still running. Try the command again, or close and reopen the session if it stays stuck.`
|
|
148
153
|
);
|
|
149
154
|
}
|
|
150
155
|
const contexts = browser.contexts();
|
|
@@ -170,14 +175,14 @@ async function connect(session, logger, timeoutMs = 1e4, options) {
|
|
|
170
175
|
}
|
|
171
176
|
if (options?.requireSinglePage && !options.pageId && pages.length > 1) {
|
|
172
177
|
throw new Error(
|
|
173
|
-
`Multiple pages are open in session "${session}". Pass --page <id> to target a page (run "libretto
|
|
178
|
+
`Multiple pages are open in session "${session}". Pass --page <id> to target a page (run "libretto pages --session ${session}" to list ids).`
|
|
174
179
|
);
|
|
175
180
|
}
|
|
176
181
|
const pageRefs = await resolvePageReferences(pages);
|
|
177
182
|
const pageRef = options?.pageId ? pageRefs.find((ref) => ref.id === options.pageId) ?? null : pageRefs[pageRefs.length - 1];
|
|
178
183
|
if (!pageRef) {
|
|
179
184
|
throw new Error(
|
|
180
|
-
`Page "${options?.pageId}" was not found in session "${session}". Run "libretto
|
|
185
|
+
`Page "${options?.pageId}" was not found in session "${session}". Run "libretto pages --session ${session}" to list ids.`
|
|
181
186
|
);
|
|
182
187
|
}
|
|
183
188
|
const page = pageRef.page;
|
|
@@ -293,7 +298,7 @@ function childLog(level, event, data = {}) {
|
|
|
293
298
|
timestamp: new Date().toISOString(),
|
|
294
299
|
id: Math.random().toString(36).slice(2, 10),
|
|
295
300
|
level,
|
|
296
|
-
scope: 'libretto
|
|
301
|
+
scope: 'libretto.child',
|
|
297
302
|
event,
|
|
298
303
|
data,
|
|
299
304
|
});
|
|
@@ -606,7 +611,7 @@ async function runCloseAll(logger, options) {
|
|
|
606
611
|
[
|
|
607
612
|
`Failed to close ${survivors.length} session(s) gracefully: ${formatSessionList(survivors)}.`,
|
|
608
613
|
`Closed ${closed} session(s).`,
|
|
609
|
-
|
|
614
|
+
`Retry with: libretto close --all --force`
|
|
610
615
|
].join("\n")
|
|
611
616
|
);
|
|
612
617
|
}
|
package/dist/cli/core/context.js
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
import { Logger, createFileLogSink } from "../../shared/logger/index.js";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
-
import { cwd } from "node:process";
|
|
4
2
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
5
|
-
import { join
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { resolveLibrettoRepoRoot } from "../../shared/paths/repo-root.js";
|
|
6
5
|
import { validateSessionName } from "./session.js";
|
|
7
|
-
|
|
8
|
-
const override = process.env.LIBRETTO_REPO_ROOT?.trim();
|
|
9
|
-
if (override) {
|
|
10
|
-
return resolve(override);
|
|
11
|
-
}
|
|
12
|
-
const result = spawnSync("git", ["rev-parse", "--show-toplevel"], {
|
|
13
|
-
encoding: "utf-8"
|
|
14
|
-
});
|
|
15
|
-
if (result.status === 0 && result.stdout) {
|
|
16
|
-
return result.stdout.trim();
|
|
17
|
-
}
|
|
18
|
-
return cwd();
|
|
19
|
-
}
|
|
20
|
-
const REPO_ROOT = getRepoRoot();
|
|
6
|
+
const REPO_ROOT = resolveLibrettoRepoRoot();
|
|
21
7
|
const LIBRETTO_CONFIG_DIR = join(REPO_ROOT, ".libretto");
|
|
22
8
|
const LIBRETTO_CONFIG_PATH = join(LIBRETTO_CONFIG_DIR, "config.json");
|
|
23
9
|
const PROFILES_DIR = join(LIBRETTO_CONFIG_DIR, "profiles");
|
|
@@ -63,7 +49,7 @@ function createLoggerForSession(session) {
|
|
|
63
49
|
const sessionDir = getSessionDir(session);
|
|
64
50
|
mkdirSync(sessionDir, { recursive: true });
|
|
65
51
|
const logFilePath = getSessionLogsPath(session);
|
|
66
|
-
return new Logger(["libretto
|
|
52
|
+
return new Logger(["libretto"], [createFileLogSink({ filePath: logFilePath })]);
|
|
67
53
|
}
|
|
68
54
|
async function closeLogger(logger) {
|
|
69
55
|
if (!logger) return;
|
package/dist/cli/core/session.js
CHANGED
|
@@ -93,7 +93,7 @@ function throwSessionNotFoundError(session) {
|
|
|
93
93
|
}
|
|
94
94
|
lines.push("");
|
|
95
95
|
lines.push("Start one with:");
|
|
96
|
-
lines.push(` libretto
|
|
96
|
+
lines.push(` libretto open <url> --session ${session}`);
|
|
97
97
|
throw new Error(lines.join("\n"));
|
|
98
98
|
}
|
|
99
99
|
function assertSessionStateExistsOrThrow(session) {
|
|
@@ -161,7 +161,7 @@ function assertSessionAvailableForStart(session, logger) {
|
|
|
161
161
|
}
|
|
162
162
|
const endpoint = `http://127.0.0.1:${existingState.port}`;
|
|
163
163
|
throw new Error(
|
|
164
|
-
`Session "${session}" is already open and connected to ${endpoint} (pid ${existingState.pid}). Create a new session or close the current one with: libretto
|
|
164
|
+
`Session "${session}" is already open and connected to ${endpoint} (pid ${existingState.pid}). Create a new session or close the current one with: libretto close --session ${session}`
|
|
165
165
|
);
|
|
166
166
|
}
|
|
167
167
|
export {
|
|
@@ -76,7 +76,7 @@ ${stripAnsi(result.stderr).trim() || stripAnsi(result.stdout).trim() || "No erro
|
|
|
76
76
|
}
|
|
77
77
|
class CodexUserCodingAgent extends UserCodingAgent {
|
|
78
78
|
async analyzeSnapshot(prompt, pngPath, logger) {
|
|
79
|
-
const tempDir = mkdtempSync(join(tmpdir(), "libretto-
|
|
79
|
+
const tempDir = mkdtempSync(join(tmpdir(), "libretto-analyzer-"));
|
|
80
80
|
const outputPath = join(
|
|
81
81
|
tempDir,
|
|
82
82
|
`snapshot-analyzer-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
|
|
@@ -171,7 +171,7 @@ async function runExternalCommand(command, args, logger, stdinText) {
|
|
|
171
171
|
if (error.code === "ENOENT") {
|
|
172
172
|
reject(
|
|
173
173
|
new Error(
|
|
174
|
-
`Command not found: ${command}. Configure AI with 'libretto
|
|
174
|
+
`Command not found: ${command}. Configure AI with 'libretto ai configure'.`
|
|
175
175
|
)
|
|
176
176
|
);
|
|
177
177
|
return;
|
package/dist/cli/router.js
CHANGED
|
@@ -17,7 +17,7 @@ function buildCLIRoutes(logger) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
function createCLIApp(logger) {
|
|
20
|
-
return SimpleCLI.define("libretto
|
|
20
|
+
return SimpleCLI.define("libretto", buildCLIRoutes(logger), {
|
|
21
21
|
globalNamed: {
|
|
22
22
|
session: sessionOption()
|
|
23
23
|
}
|
|
@@ -77,9 +77,9 @@ function getMissingLocalAuthProfileError(args) {
|
|
|
77
77
|
`Local auth profile not found for domain "${normalizedDomain}".`,
|
|
78
78
|
`Expected profile file: ${args.profilePath}`,
|
|
79
79
|
"To create it:",
|
|
80
|
-
` 1. libretto
|
|
80
|
+
` 1. libretto open https://${normalizedDomain} --headed --session ${args.session}`,
|
|
81
81
|
" 2. Log in manually in the browser window.",
|
|
82
|
-
` 3. libretto
|
|
82
|
+
` 3. libretto save ${normalizedDomain} --session ${args.session}`
|
|
83
83
|
].join("\n");
|
|
84
84
|
}
|
|
85
85
|
function getAbsoluteIntegrationPath(integrationPath) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { mkdirSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { resolveLibrettoRepoRoot } from "./repo-root.js";
|
|
3
4
|
const LIBRETTO_DIRNAME = ".libretto";
|
|
4
5
|
const LIBRETTO_SESSIONS_DIRNAME = "sessions";
|
|
5
6
|
const SESSION_STATE_FILENAME = "state.json";
|
|
@@ -8,7 +9,7 @@ const RUNNER_LOG_FILENAME = "logs.jsonl";
|
|
|
8
9
|
const PAUSED_SIGNAL_SUFFIX = "paused";
|
|
9
10
|
const RESUME_SIGNAL_SUFFIX = "resume";
|
|
10
11
|
function getLibrettoRoot(cwd = process.cwd()) {
|
|
11
|
-
return join(cwd, LIBRETTO_DIRNAME);
|
|
12
|
+
return join(resolveLibrettoRepoRoot(cwd), LIBRETTO_DIRNAME);
|
|
12
13
|
}
|
|
13
14
|
function getLibrettoSessionsDir(cwd = process.cwd()) {
|
|
14
15
|
return join(getLibrettoRoot(cwd), LIBRETTO_SESSIONS_DIRNAME);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
const repoRootCache = /* @__PURE__ */ new Map();
|
|
4
|
+
function resolveLibrettoRepoRoot(cwd = process.cwd()) {
|
|
5
|
+
const override = process.env.LIBRETTO_REPO_ROOT?.trim();
|
|
6
|
+
if (override) {
|
|
7
|
+
return resolve(override);
|
|
8
|
+
}
|
|
9
|
+
const normalizedCwd = resolve(cwd);
|
|
10
|
+
const cached = repoRootCache.get(normalizedCwd);
|
|
11
|
+
if (cached) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
const result = spawnSync("git", ["rev-parse", "--show-toplevel"], {
|
|
15
|
+
cwd: normalizedCwd,
|
|
16
|
+
encoding: "utf-8"
|
|
17
|
+
});
|
|
18
|
+
const repoRoot = result.status === 0 && result.stdout ? result.stdout.trim() : normalizedCwd;
|
|
19
|
+
repoRootCache.set(normalizedCwd, repoRoot);
|
|
20
|
+
return repoRoot;
|
|
21
|
+
}
|
|
22
|
+
export {
|
|
23
|
+
resolveLibrettoRepoRoot
|
|
24
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libretto",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "AI-powered browser automation library and CLI built on Playwright",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -14,25 +14,24 @@
|
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
16
|
"dist",
|
|
17
|
+
"src",
|
|
17
18
|
"scripts",
|
|
18
19
|
"skills/libretto"
|
|
19
20
|
],
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
20
22
|
"bin": {
|
|
21
|
-
"libretto": "./dist/cli/index.js"
|
|
22
|
-
"libretto-cli": "./dist/cli/index.js"
|
|
23
|
+
"libretto": "./dist/cli/index.js"
|
|
23
24
|
},
|
|
24
25
|
"exports": {
|
|
25
26
|
".": {
|
|
26
27
|
"types": "./dist/index.d.ts",
|
|
27
28
|
"import": "./dist/index.js",
|
|
28
|
-
"
|
|
29
|
+
"default": "./dist/index.js"
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
"scripts": {
|
|
32
33
|
"postinstall": "node scripts/postinstall.mjs",
|
|
33
|
-
"build": "
|
|
34
|
-
"build:runtime": "tsup --config tsup.config.ts",
|
|
35
|
-
"build:cli": "tsup --config tsup.cli.config.ts",
|
|
34
|
+
"build": "tsup --config tsup.config.ts",
|
|
36
35
|
"type-check": "tsc --noEmit",
|
|
37
36
|
"test": "pnpm run build && vitest run",
|
|
38
37
|
"eval": "pnpm run build && vitest run --config vitest.evals.config.ts",
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -14,15 +14,24 @@ spawnSync("npx", ["playwright", "install", "chromium"], {
|
|
|
14
14
|
shell: true,
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
const installCwd = process.env.INIT_CWD?.trim() || null;
|
|
18
|
+
if (!installCwd) {
|
|
19
|
+
console.warn(
|
|
20
|
+
"libretto: automatic skill install failed because INIT_CWD is not set. Run `npx skills add saffron-health/libretto` to add the skills manually.",
|
|
21
|
+
);
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Resolve the consuming project's repo root from the original install cwd,
|
|
26
|
+
// not pnpm's content-addressable store path.
|
|
18
27
|
const gitResult = spawnSync("git", ["rev-parse", "--show-toplevel"], {
|
|
28
|
+
cwd: installCwd,
|
|
19
29
|
encoding: "utf-8",
|
|
20
30
|
stdio: ["pipe", "pipe", "pipe"],
|
|
21
31
|
});
|
|
22
32
|
const repoRoot = gitResult.status === 0 && gitResult.stdout
|
|
23
33
|
? gitResult.stdout.trim()
|
|
24
|
-
:
|
|
25
|
-
if (!repoRoot) process.exit(0);
|
|
34
|
+
: installCwd;
|
|
26
35
|
|
|
27
36
|
// Sync skills to any agent dirs at repo root
|
|
28
37
|
const sourceDir = join(packageRoot, "skills", "libretto");
|