libretto 0.4.2 → 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.
Files changed (161) hide show
  1. package/dist/cli/cli.js +20 -19
  2. package/dist/cli/commands/ai.js +1 -1
  3. package/dist/cli/commands/browser.js +3 -3
  4. package/dist/cli/commands/execution.js +3 -3
  5. package/dist/cli/commands/init.js +30 -21
  6. package/dist/cli/commands/logs.js +1 -1
  7. package/dist/cli/commands/snapshot.js +6 -1
  8. package/dist/cli/core/ai-config.js +62 -12
  9. package/dist/cli/core/browser.js +11 -6
  10. package/dist/cli/core/context.js +4 -18
  11. package/dist/cli/core/session.js +2 -2
  12. package/dist/cli/core/snapshot-analyzer.js +2 -2
  13. package/dist/cli/core/snapshot-api-config.js +46 -5
  14. package/dist/cli/router.js +1 -1
  15. package/dist/cli/workers/run-integration-runtime.js +2 -4
  16. package/dist/shared/debug/index.d.ts +1 -1
  17. package/dist/shared/debug/index.js +2 -3
  18. package/dist/shared/debug/pause.d.ts +2 -6
  19. package/dist/shared/debug/pause.js +27 -20
  20. package/dist/shared/llm/client.js +5 -5
  21. package/dist/shared/paths/paths.js +2 -1
  22. package/dist/shared/paths/repo-root.d.ts +3 -0
  23. package/dist/shared/paths/repo-root.js +24 -0
  24. package/package.json +8 -8
  25. package/scripts/postinstall.mjs +50 -0
  26. package/skills/libretto/SKILL.md +93 -404
  27. package/skills/libretto/references/auth-profiles.md +30 -0
  28. package/skills/libretto/references/pages-and-page-targeting.md +29 -0
  29. package/skills/libretto/references/reverse-engineering-network-requests.md +39 -0
  30. package/skills/libretto/references/user-action-log.md +31 -0
  31. package/src/cli/cli.ts +173 -0
  32. package/src/cli/commands/ai.ts +35 -0
  33. package/src/cli/commands/browser.ts +165 -0
  34. package/src/cli/commands/execution.ts +691 -0
  35. package/src/cli/commands/init.ts +327 -0
  36. package/src/cli/commands/logs.ts +128 -0
  37. package/src/cli/commands/shared.ts +70 -0
  38. package/src/cli/commands/snapshot.ts +327 -0
  39. package/src/cli/core/ai-config.ts +255 -0
  40. package/src/cli/core/api-snapshot-analyzer.ts +97 -0
  41. package/src/cli/core/browser.ts +839 -0
  42. package/src/cli/core/context.ts +122 -0
  43. package/src/cli/core/pause-signals.ts +35 -0
  44. package/src/cli/core/session-telemetry.ts +553 -0
  45. package/src/cli/core/session.ts +209 -0
  46. package/src/cli/core/snapshot-analyzer.ts +875 -0
  47. package/src/cli/core/snapshot-api-config.ts +236 -0
  48. package/src/cli/core/telemetry.ts +446 -0
  49. package/src/cli/framework/simple-cli.ts +1273 -0
  50. package/src/cli/index.ts +13 -0
  51. package/src/cli/router.ts +28 -0
  52. package/src/cli/workers/run-integration-runtime.ts +311 -0
  53. package/src/cli/workers/run-integration-worker-protocol.ts +14 -0
  54. package/src/cli/workers/run-integration-worker.ts +75 -0
  55. package/src/index.ts +120 -0
  56. package/src/runtime/download/download.ts +100 -0
  57. package/src/runtime/download/index.ts +7 -0
  58. package/src/runtime/extract/extract.ts +92 -0
  59. package/src/runtime/extract/index.ts +1 -0
  60. package/src/runtime/network/index.ts +5 -0
  61. package/src/runtime/network/network.ts +113 -0
  62. package/src/runtime/recovery/agent.ts +256 -0
  63. package/src/runtime/recovery/errors.ts +152 -0
  64. package/src/runtime/recovery/index.ts +7 -0
  65. package/src/runtime/recovery/recovery.ts +50 -0
  66. package/{dist/shared/condense-dom/condense-dom.cjs → src/shared/condense-dom/condense-dom.ts} +243 -115
  67. package/src/shared/config/config.ts +22 -0
  68. package/src/shared/config/index.ts +5 -0
  69. package/src/shared/debug/index.ts +1 -0
  70. package/src/shared/debug/pause.ts +85 -0
  71. package/src/shared/instrumentation/errors.ts +82 -0
  72. package/src/shared/instrumentation/index.ts +9 -0
  73. package/src/shared/instrumentation/instrument.ts +276 -0
  74. package/src/shared/llm/ai-sdk-adapter.ts +78 -0
  75. package/src/shared/llm/client.ts +217 -0
  76. package/src/shared/llm/index.ts +3 -0
  77. package/src/shared/llm/types.ts +63 -0
  78. package/src/shared/logger/index.ts +6 -0
  79. package/src/shared/logger/logger.ts +352 -0
  80. package/src/shared/logger/sinks.ts +144 -0
  81. package/src/shared/paths/paths.ts +109 -0
  82. package/src/shared/paths/repo-root.ts +27 -0
  83. package/src/shared/run/api.ts +2 -0
  84. package/src/shared/run/browser.ts +98 -0
  85. package/src/shared/state/index.ts +11 -0
  86. package/src/shared/state/session-state.ts +74 -0
  87. package/src/shared/visualization/ghost-cursor.ts +200 -0
  88. package/src/shared/visualization/highlight.ts +146 -0
  89. package/src/shared/visualization/index.ts +18 -0
  90. package/src/shared/workflow/workflow.ts +42 -0
  91. package/dist/index.cjs +0 -144
  92. package/dist/index.d.cts +0 -21
  93. package/dist/runtime/download/download.cjs +0 -70
  94. package/dist/runtime/download/download.d.cts +0 -35
  95. package/dist/runtime/download/index.cjs +0 -30
  96. package/dist/runtime/download/index.d.cts +0 -3
  97. package/dist/runtime/extract/extract.cjs +0 -88
  98. package/dist/runtime/extract/extract.d.cts +0 -23
  99. package/dist/runtime/extract/index.cjs +0 -28
  100. package/dist/runtime/extract/index.d.cts +0 -5
  101. package/dist/runtime/network/index.cjs +0 -28
  102. package/dist/runtime/network/index.d.cts +0 -4
  103. package/dist/runtime/network/network.cjs +0 -91
  104. package/dist/runtime/network/network.d.cts +0 -28
  105. package/dist/runtime/recovery/agent.cjs +0 -223
  106. package/dist/runtime/recovery/agent.d.cts +0 -13
  107. package/dist/runtime/recovery/errors.cjs +0 -124
  108. package/dist/runtime/recovery/errors.d.cts +0 -31
  109. package/dist/runtime/recovery/index.cjs +0 -34
  110. package/dist/runtime/recovery/index.d.cts +0 -7
  111. package/dist/runtime/recovery/recovery.cjs +0 -55
  112. package/dist/runtime/recovery/recovery.d.cts +0 -12
  113. package/dist/shared/condense-dom/condense-dom.d.cts +0 -34
  114. package/dist/shared/config/config.cjs +0 -44
  115. package/dist/shared/config/config.d.cts +0 -10
  116. package/dist/shared/config/index.cjs +0 -32
  117. package/dist/shared/config/index.d.cts +0 -1
  118. package/dist/shared/debug/index.cjs +0 -30
  119. package/dist/shared/debug/index.d.cts +0 -1
  120. package/dist/shared/debug/pause.cjs +0 -90
  121. package/dist/shared/debug/pause.d.cts +0 -16
  122. package/dist/shared/instrumentation/errors.cjs +0 -81
  123. package/dist/shared/instrumentation/errors.d.cts +0 -12
  124. package/dist/shared/instrumentation/index.cjs +0 -35
  125. package/dist/shared/instrumentation/index.d.cts +0 -6
  126. package/dist/shared/instrumentation/instrument.cjs +0 -206
  127. package/dist/shared/instrumentation/instrument.d.cts +0 -32
  128. package/dist/shared/llm/ai-sdk-adapter.cjs +0 -71
  129. package/dist/shared/llm/ai-sdk-adapter.d.cts +0 -22
  130. package/dist/shared/llm/client.cjs +0 -218
  131. package/dist/shared/llm/client.d.cts +0 -13
  132. package/dist/shared/llm/index.cjs +0 -31
  133. package/dist/shared/llm/index.d.cts +0 -5
  134. package/dist/shared/llm/types.cjs +0 -16
  135. package/dist/shared/llm/types.d.cts +0 -67
  136. package/dist/shared/logger/index.cjs +0 -37
  137. package/dist/shared/logger/index.d.cts +0 -2
  138. package/dist/shared/logger/logger.cjs +0 -232
  139. package/dist/shared/logger/logger.d.cts +0 -86
  140. package/dist/shared/logger/sinks.cjs +0 -160
  141. package/dist/shared/logger/sinks.d.cts +0 -9
  142. package/dist/shared/paths/paths.cjs +0 -104
  143. package/dist/shared/paths/paths.d.cts +0 -10
  144. package/dist/shared/run/api.cjs +0 -28
  145. package/dist/shared/run/api.d.cts +0 -2
  146. package/dist/shared/run/browser.cjs +0 -98
  147. package/dist/shared/run/browser.d.cts +0 -22
  148. package/dist/shared/state/index.cjs +0 -38
  149. package/dist/shared/state/index.d.cts +0 -2
  150. package/dist/shared/state/session-state.cjs +0 -92
  151. package/dist/shared/state/session-state.d.cts +0 -40
  152. package/dist/shared/visualization/ghost-cursor.cjs +0 -174
  153. package/dist/shared/visualization/ghost-cursor.d.cts +0 -37
  154. package/dist/shared/visualization/highlight.cjs +0 -134
  155. package/dist/shared/visualization/highlight.d.cts +0 -22
  156. package/dist/shared/visualization/index.cjs +0 -45
  157. package/dist/shared/visualization/index.d.cts +0 -3
  158. package/dist/shared/workflow/workflow.cjs +0 -47
  159. package/dist/shared/workflow/workflow.d.cts +0 -21
  160. package/skills/libretto/code-generation-rules.md +0 -223
  161. package/skills/libretto/integration-approach-selection.md +0 -174
@@ -1,7 +1,3 @@
1
- /**
2
- * Called by the CLI runtime to make the session name available to `pause()`.
3
- */
4
- declare function setSessionForPause(session: string): void;
5
1
  /**
6
2
  * Standalone pause function.
7
3
  *
@@ -11,6 +7,6 @@ declare function setSessionForPause(session: string): void;
11
7
  *
12
8
  * Import directly: `import { pause } from "libretto";`
13
9
  */
14
- declare function pause(): Promise<void>;
10
+ declare function pause(session: string): Promise<void>;
15
11
 
16
- export { pause, setSessionForPause };
12
+ export { pause };
@@ -1,32 +1,40 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { mkdir, writeFile } from "node:fs/promises";
3
- let _sessionName;
4
- function setSessionForPause(session) {
5
- _sessionName = session;
6
- }
7
- function getSessionFromProcessArgs() {
8
- const rawPayload = process.argv[2];
9
- if (!rawPayload) return void 0;
3
+ import { getSessionDir } from "../../cli/core/context.js";
4
+ import { getPauseSignalPaths, removeSignalIfExists } from "../../cli/core/pause-signals.js";
5
+ import { listSessionsWithStateFile, readSessionState } from "../../cli/core/session.js";
6
+ function isPidRunning(pid) {
10
7
  try {
11
- const parsed = JSON.parse(rawPayload);
12
- return typeof parsed.session === "string" ? parsed.session : void 0;
8
+ process.kill(pid, 0);
9
+ return true;
13
10
  } catch {
14
- return void 0;
11
+ return false;
15
12
  }
16
13
  }
17
- function resolveSession() {
18
- return _sessionName ?? getSessionFromProcessArgs();
14
+ function getRunningSessions() {
15
+ return listSessionsWithStateFile().filter((candidate) => {
16
+ const state = readSessionState(candidate);
17
+ return state !== null && isPidRunning(state.pid);
18
+ });
19
+ }
20
+ function throwMissingSessionError() {
21
+ const runningSessions = getRunningSessions();
22
+ const lines = ["pause(session) requires a non-empty session ID."];
23
+ if (runningSessions.length > 0) {
24
+ lines.push("", "Running sessions:");
25
+ for (const runningSession of runningSessions) {
26
+ lines.push(` ${runningSession}`);
27
+ }
28
+ }
29
+ throw new Error(lines.join("\n"));
19
30
  }
20
- async function pause() {
31
+ async function pause(session) {
21
32
  if (process.env.NODE_ENV === "production") {
22
33
  return;
23
34
  }
24
- const session = resolveSession();
25
- if (!session) {
26
- return;
35
+ if (typeof session !== "string" || session.trim().length === 0) {
36
+ throwMissingSessionError();
27
37
  }
28
- const { getPauseSignalPaths, removeSignalIfExists } = await import("../../cli/core/pause-signals.js");
29
- const { getSessionDir } = await import("../../cli/core/context.js");
30
38
  const signalPaths = getPauseSignalPaths(session);
31
39
  const { pausedSignalPath, resumeSignalPath } = signalPaths;
32
40
  await mkdir(getSessionDir(session), { recursive: true });
@@ -50,6 +58,5 @@ async function pause() {
50
58
  console.log("[pause] Resume signal received. Continuing workflow...");
51
59
  }
52
60
  export {
53
- pause,
54
- setSessionForPause
61
+ pause
55
62
  };
@@ -26,7 +26,7 @@ function parseModel(model) {
26
26
  const slashIndex = model.indexOf("/");
27
27
  if (slashIndex === -1) {
28
28
  throw new Error(
29
- `Invalid model string "${model}". Expected format: "provider/model-id" (for example "openai/gpt-5.4", "anthropic/claude-sonnet-4-6", "google/gemini-2.5-pro", or "vertex/gemini-2.5-pro").`
29
+ `Invalid model string "${model}". Expected format: "provider/model-id" (for example "openai/gpt-5.4", "anthropic/claude-sonnet-4-6", "google/gemini-3-flash-preview", or "vertex/gemini-2.5-pro").`
30
30
  );
31
31
  }
32
32
  const providerInput = model.slice(0, slashIndex).toLowerCase();
@@ -54,14 +54,14 @@ function hasProviderCredentials(provider, env = process.env) {
54
54
  function missingProviderCredentialsMessage(provider) {
55
55
  switch (provider) {
56
56
  case "google":
57
- return "Missing Gemini API key. Set GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY.";
57
+ return "Gemini API key is missing. Set GEMINI_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY.";
58
58
  case "vertex":
59
- return "Missing Vertex AI project. Set GOOGLE_CLOUD_PROJECT (or GCLOUD_PROJECT) and ensure application default credentials are configured.";
59
+ return "Vertex AI project is missing. Set GOOGLE_CLOUD_PROJECT (or GCLOUD_PROJECT) and ensure application default credentials are configured.";
60
60
  case "anthropic": {
61
- return "Missing Anthropic API key. Set ANTHROPIC_API_KEY.";
61
+ return "Anthropic API key is missing. Set ANTHROPIC_API_KEY.";
62
62
  }
63
63
  case "openai": {
64
- return "Missing OpenAI API key. Set OPENAI_API_KEY.";
64
+ return "OpenAI API key is missing. Set OPENAI_API_KEY.";
65
65
  }
66
66
  }
67
67
  }
@@ -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,3 @@
1
+ declare function resolveLibrettoRepoRoot(cwd?: string): string;
2
+
3
+ export { resolveLibrettoRepoRoot };
@@ -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.4.2",
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,24 +14,24 @@
14
14
  },
15
15
  "files": [
16
16
  "dist",
17
+ "src",
18
+ "scripts",
17
19
  "skills/libretto"
18
20
  ],
21
+ "types": "./dist/index.d.ts",
19
22
  "bin": {
20
- "libretto": "./dist/cli/index.js",
21
- "libretto-cli": "./dist/cli/index.js"
23
+ "libretto": "./dist/cli/index.js"
22
24
  },
23
25
  "exports": {
24
26
  ".": {
25
27
  "types": "./dist/index.d.ts",
26
28
  "import": "./dist/index.js",
27
- "require": "./dist/index.cjs"
29
+ "default": "./dist/index.js"
28
30
  }
29
31
  },
30
32
  "scripts": {
31
- "postinstall": "playwright install chromium",
32
- "build": "pnpm run build:runtime && pnpm run build:cli",
33
- "build:runtime": "tsup --config tsup.config.ts",
34
- "build:cli": "tsup --config tsup.cli.config.ts",
33
+ "postinstall": "node scripts/postinstall.mjs",
34
+ "build": "tsup --config tsup.config.ts",
35
35
  "type-check": "tsc --noEmit",
36
36
  "test": "pnpm run build && vitest run",
37
37
  "eval": "pnpm run build && vitest run --config vitest.evals.config.ts",
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from "node:fs";
4
+ import { dirname, join } from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ const packageRoot = join(__dirname, "..");
10
+
11
+ // Install Playwright Chromium
12
+ spawnSync("npx", ["playwright", "install", "chromium"], {
13
+ stdio: "inherit",
14
+ shell: true,
15
+ });
16
+
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.
27
+ const gitResult = spawnSync("git", ["rev-parse", "--show-toplevel"], {
28
+ cwd: installCwd,
29
+ encoding: "utf-8",
30
+ stdio: ["pipe", "pipe", "pipe"],
31
+ });
32
+ const repoRoot = gitResult.status === 0 && gitResult.stdout
33
+ ? gitResult.stdout.trim()
34
+ : installCwd;
35
+
36
+ // Sync skills to any agent dirs at repo root
37
+ const sourceDir = join(packageRoot, "skills", "libretto");
38
+ if (!existsSync(sourceDir)) process.exit(0);
39
+
40
+ const agentDirNames = [".agents", ".claude"];
41
+ for (const name of agentDirNames) {
42
+ const agentDir = join(repoRoot, name);
43
+ if (!existsSync(agentDir)) continue;
44
+ const dest = join(agentDir, "skills", "libretto");
45
+ if (existsSync(dest)) rmSync(dest, { recursive: true });
46
+ mkdirSync(dirname(dest), { recursive: true });
47
+ cpSync(sourceDir, dest, { recursive: true });
48
+ const count = readdirSync(dest).length;
49
+ console.log(`libretto: synced ${count} skill files to ${dest}`);
50
+ }