libretto 0.2.6 → 0.3.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 (160) hide show
  1. package/LICENSE +21 -0
  2. package/package.json +12 -12
  3. package/skill/SKILL.md +20 -18
  4. package/skill/code-generation-rules.md +3 -3
  5. package/skill/integration-approach-selection.md +3 -3
  6. package/dist/cli/cli.js +0 -209
  7. package/dist/cli/commands/ai.js +0 -21
  8. package/dist/cli/commands/browser.js +0 -82
  9. package/dist/cli/commands/execution.js +0 -461
  10. package/dist/cli/commands/init.js +0 -95
  11. package/dist/cli/commands/logs.js +0 -93
  12. package/dist/cli/commands/snapshot.js +0 -106
  13. package/dist/cli/core/ai-config.js +0 -149
  14. package/dist/cli/core/browser.js +0 -648
  15. package/dist/cli/core/context.js +0 -118
  16. package/dist/cli/core/pause-signals.js +0 -29
  17. package/dist/cli/core/session-telemetry.js +0 -491
  18. package/dist/cli/core/session.js +0 -183
  19. package/dist/cli/core/snapshot-analyzer.js +0 -492
  20. package/dist/cli/core/telemetry.js +0 -362
  21. package/dist/cli/index.js +0 -13
  22. package/dist/cli/workers/run-integration-runtime.js +0 -227
  23. package/dist/cli/workers/run-integration-worker-protocol.js +0 -12
  24. package/dist/cli/workers/run-integration-worker.js +0 -66
  25. package/dist/index.cjs +0 -116
  26. package/dist/index.d.cts +0 -21
  27. package/dist/index.d.ts +0 -21
  28. package/dist/index.js +0 -97
  29. package/dist/runtime/download/download.cjs +0 -70
  30. package/dist/runtime/download/download.d.cts +0 -35
  31. package/dist/runtime/download/download.d.ts +0 -35
  32. package/dist/runtime/download/download.js +0 -45
  33. package/dist/runtime/download/index.cjs +0 -30
  34. package/dist/runtime/download/index.d.cts +0 -3
  35. package/dist/runtime/download/index.d.ts +0 -3
  36. package/dist/runtime/download/index.js +0 -8
  37. package/dist/runtime/extract/extract.cjs +0 -88
  38. package/dist/runtime/extract/extract.d.cts +0 -23
  39. package/dist/runtime/extract/extract.d.ts +0 -23
  40. package/dist/runtime/extract/extract.js +0 -64
  41. package/dist/runtime/extract/index.cjs +0 -28
  42. package/dist/runtime/extract/index.d.cts +0 -5
  43. package/dist/runtime/extract/index.d.ts +0 -5
  44. package/dist/runtime/extract/index.js +0 -4
  45. package/dist/runtime/network/index.cjs +0 -28
  46. package/dist/runtime/network/index.d.cts +0 -4
  47. package/dist/runtime/network/index.d.ts +0 -4
  48. package/dist/runtime/network/index.js +0 -6
  49. package/dist/runtime/network/network.cjs +0 -91
  50. package/dist/runtime/network/network.d.cts +0 -28
  51. package/dist/runtime/network/network.d.ts +0 -28
  52. package/dist/runtime/network/network.js +0 -67
  53. package/dist/runtime/recovery/agent.cjs +0 -223
  54. package/dist/runtime/recovery/agent.d.cts +0 -13
  55. package/dist/runtime/recovery/agent.d.ts +0 -13
  56. package/dist/runtime/recovery/agent.js +0 -199
  57. package/dist/runtime/recovery/errors.cjs +0 -124
  58. package/dist/runtime/recovery/errors.d.cts +0 -31
  59. package/dist/runtime/recovery/errors.d.ts +0 -31
  60. package/dist/runtime/recovery/errors.js +0 -100
  61. package/dist/runtime/recovery/index.cjs +0 -34
  62. package/dist/runtime/recovery/index.d.cts +0 -7
  63. package/dist/runtime/recovery/index.d.ts +0 -7
  64. package/dist/runtime/recovery/index.js +0 -10
  65. package/dist/runtime/recovery/recovery.cjs +0 -55
  66. package/dist/runtime/recovery/recovery.d.cts +0 -12
  67. package/dist/runtime/recovery/recovery.d.ts +0 -12
  68. package/dist/runtime/recovery/recovery.js +0 -31
  69. package/dist/shared/config/config.cjs +0 -44
  70. package/dist/shared/config/config.d.cts +0 -10
  71. package/dist/shared/config/config.d.ts +0 -10
  72. package/dist/shared/config/config.js +0 -18
  73. package/dist/shared/config/index.cjs +0 -32
  74. package/dist/shared/config/index.d.cts +0 -1
  75. package/dist/shared/config/index.d.ts +0 -1
  76. package/dist/shared/config/index.js +0 -10
  77. package/dist/shared/debug/index.cjs +0 -30
  78. package/dist/shared/debug/index.d.cts +0 -1
  79. package/dist/shared/debug/index.d.ts +0 -1
  80. package/dist/shared/debug/index.js +0 -5
  81. package/dist/shared/debug/pause.cjs +0 -90
  82. package/dist/shared/debug/pause.d.cts +0 -16
  83. package/dist/shared/debug/pause.d.ts +0 -16
  84. package/dist/shared/debug/pause.js +0 -55
  85. package/dist/shared/instrumentation/errors.cjs +0 -81
  86. package/dist/shared/instrumentation/errors.d.cts +0 -12
  87. package/dist/shared/instrumentation/errors.d.ts +0 -12
  88. package/dist/shared/instrumentation/errors.js +0 -57
  89. package/dist/shared/instrumentation/index.cjs +0 -35
  90. package/dist/shared/instrumentation/index.d.cts +0 -6
  91. package/dist/shared/instrumentation/index.d.ts +0 -6
  92. package/dist/shared/instrumentation/index.js +0 -12
  93. package/dist/shared/instrumentation/instrument.cjs +0 -206
  94. package/dist/shared/instrumentation/instrument.d.cts +0 -32
  95. package/dist/shared/instrumentation/instrument.d.ts +0 -32
  96. package/dist/shared/instrumentation/instrument.js +0 -190
  97. package/dist/shared/llm/ai-sdk-adapter.cjs +0 -67
  98. package/dist/shared/llm/ai-sdk-adapter.d.cts +0 -22
  99. package/dist/shared/llm/ai-sdk-adapter.d.ts +0 -22
  100. package/dist/shared/llm/ai-sdk-adapter.js +0 -43
  101. package/dist/shared/llm/client.cjs +0 -139
  102. package/dist/shared/llm/client.d.cts +0 -6
  103. package/dist/shared/llm/client.d.ts +0 -6
  104. package/dist/shared/llm/client.js +0 -115
  105. package/dist/shared/llm/index.cjs +0 -31
  106. package/dist/shared/llm/index.d.cts +0 -5
  107. package/dist/shared/llm/index.d.ts +0 -5
  108. package/dist/shared/llm/index.js +0 -6
  109. package/dist/shared/llm/types.cjs +0 -16
  110. package/dist/shared/llm/types.d.cts +0 -66
  111. package/dist/shared/llm/types.d.ts +0 -66
  112. package/dist/shared/llm/types.js +0 -0
  113. package/dist/shared/logger/index.cjs +0 -37
  114. package/dist/shared/logger/index.d.cts +0 -2
  115. package/dist/shared/logger/index.d.ts +0 -2
  116. package/dist/shared/logger/index.js +0 -13
  117. package/dist/shared/logger/logger.cjs +0 -213
  118. package/dist/shared/logger/logger.d.cts +0 -82
  119. package/dist/shared/logger/logger.d.ts +0 -82
  120. package/dist/shared/logger/logger.js +0 -188
  121. package/dist/shared/logger/sinks.cjs +0 -160
  122. package/dist/shared/logger/sinks.d.cts +0 -9
  123. package/dist/shared/logger/sinks.d.ts +0 -9
  124. package/dist/shared/logger/sinks.js +0 -124
  125. package/dist/shared/paths/paths.cjs +0 -104
  126. package/dist/shared/paths/paths.d.cts +0 -10
  127. package/dist/shared/paths/paths.d.ts +0 -10
  128. package/dist/shared/paths/paths.js +0 -73
  129. package/dist/shared/run/api.cjs +0 -28
  130. package/dist/shared/run/api.d.cts +0 -2
  131. package/dist/shared/run/api.d.ts +0 -2
  132. package/dist/shared/run/api.js +0 -4
  133. package/dist/shared/run/browser.cjs +0 -98
  134. package/dist/shared/run/browser.d.cts +0 -22
  135. package/dist/shared/run/browser.d.ts +0 -22
  136. package/dist/shared/run/browser.js +0 -74
  137. package/dist/shared/state/index.cjs +0 -38
  138. package/dist/shared/state/index.d.cts +0 -2
  139. package/dist/shared/state/index.d.ts +0 -2
  140. package/dist/shared/state/index.js +0 -16
  141. package/dist/shared/state/session-state.cjs +0 -85
  142. package/dist/shared/state/session-state.d.cts +0 -34
  143. package/dist/shared/state/session-state.d.ts +0 -34
  144. package/dist/shared/state/session-state.js +0 -56
  145. package/dist/shared/visualization/ghost-cursor.cjs +0 -174
  146. package/dist/shared/visualization/ghost-cursor.d.cts +0 -37
  147. package/dist/shared/visualization/ghost-cursor.d.ts +0 -37
  148. package/dist/shared/visualization/ghost-cursor.js +0 -145
  149. package/dist/shared/visualization/highlight.cjs +0 -134
  150. package/dist/shared/visualization/highlight.d.cts +0 -22
  151. package/dist/shared/visualization/highlight.d.ts +0 -22
  152. package/dist/shared/visualization/highlight.js +0 -108
  153. package/dist/shared/visualization/index.cjs +0 -45
  154. package/dist/shared/visualization/index.d.cts +0 -3
  155. package/dist/shared/visualization/index.d.ts +0 -3
  156. package/dist/shared/visualization/index.js +0 -24
  157. package/dist/shared/workflow/workflow.cjs +0 -47
  158. package/dist/shared/workflow/workflow.d.cts +0 -21
  159. package/dist/shared/workflow/workflow.d.ts +0 -21
  160. package/dist/shared/workflow/workflow.js +0 -21
@@ -1,118 +0,0 @@
1
- import { Logger, createFileLogSink } from "../../shared/logger/index.js";
2
- import { spawnSync } from "node:child_process";
3
- import { cwd } from "node:process";
4
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
5
- import { join } from "node:path";
6
- import { validateSessionName } from "./session.js";
7
- function getRepoRoot() {
8
- const result = spawnSync("git", ["rev-parse", "--show-toplevel"], {
9
- encoding: "utf-8"
10
- });
11
- if (result.status === 0 && result.stdout) {
12
- return result.stdout.trim();
13
- }
14
- return cwd();
15
- }
16
- const REPO_ROOT = getRepoRoot();
17
- const LIBRETTO_CONFIG_DIR = join(REPO_ROOT, ".libretto");
18
- const LIBRETTO_CONFIG_PATH = join(LIBRETTO_CONFIG_DIR, "config.json");
19
- const PROFILES_DIR = join(LIBRETTO_CONFIG_DIR, "profiles");
20
- const LIBRETTO_SESSIONS_DIR = join(LIBRETTO_CONFIG_DIR, "sessions");
21
- const LIBRETTO_GITIGNORE_PATH = join(LIBRETTO_CONFIG_DIR, ".gitignore");
22
- const LIBRETTO_GITIGNORE_CONTENT = [
23
- "# Local libretto runtime state",
24
- "sessions/",
25
- "profiles/",
26
- ""
27
- ].join("\n");
28
- function getSessionDir(session) {
29
- return join(LIBRETTO_SESSIONS_DIR, session);
30
- }
31
- function getSessionStatePath(session) {
32
- return join(getSessionDir(session), "state.json");
33
- }
34
- function getSessionLogsPath(session) {
35
- return join(getSessionDir(session), "logs.jsonl");
36
- }
37
- function getSessionNetworkLogPath(session) {
38
- return join(getSessionDir(session), "network.jsonl");
39
- }
40
- function getSessionActionsLogPath(session) {
41
- return join(getSessionDir(session), "actions.jsonl");
42
- }
43
- function getSessionSnapshotsDir(session) {
44
- return join(getSessionDir(session), "snapshots");
45
- }
46
- function getSessionSnapshotRunDir(session, snapshotRunId) {
47
- return join(getSessionSnapshotsDir(session), snapshotRunId);
48
- }
49
- function ensureLibrettoSetup() {
50
- mkdirSync(LIBRETTO_CONFIG_DIR, { recursive: true });
51
- mkdirSync(LIBRETTO_SESSIONS_DIR, { recursive: true });
52
- mkdirSync(PROFILES_DIR, { recursive: true });
53
- if (!existsSync(LIBRETTO_GITIGNORE_PATH)) {
54
- writeFileSync(LIBRETTO_GITIGNORE_PATH, LIBRETTO_GITIGNORE_CONTENT, "utf-8");
55
- }
56
- const agentsSkillsDir = join(REPO_ROOT, ".agents", "skills", "libretto");
57
- const claudeSkillsDir = join(REPO_ROOT, ".claude", "skills", "libretto");
58
- if (!existsSync(agentsSkillsDir) && !existsSync(claudeSkillsDir)) {
59
- console.log("[libretto] Skills not installed. Run 'npx libretto init' to complete setup.");
60
- }
61
- }
62
- function createLoggerForSession(session) {
63
- validateSessionName(session);
64
- const sessionDir = getSessionDir(session);
65
- mkdirSync(sessionDir, { recursive: true });
66
- const logFilePath = getSessionLogsPath(session);
67
- return new Logger(["libretto-cli"], [createFileLogSink({ filePath: logFilePath })]);
68
- }
69
- async function closeLogger(logger) {
70
- if (!logger) return;
71
- await logger.close();
72
- }
73
- async function withSessionLogger(session, run) {
74
- const logger = createLoggerForSession(session);
75
- try {
76
- return await run(logger);
77
- } finally {
78
- await closeLogger(logger);
79
- }
80
- }
81
- let llmClientFactory = null;
82
- function setLLMClientFactory(factory) {
83
- llmClientFactory = factory;
84
- }
85
- function getLLMClientFactory() {
86
- return llmClientFactory;
87
- }
88
- function maybeConfigureLLMClientFactoryFromEnv() {
89
- if (llmClientFactory) return;
90
- const hasAnyCreds = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT || process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
91
- if (!hasAnyCreds) return;
92
- setLLMClientFactory(async (_logger, model) => {
93
- const { createLLMClient } = await import("../../shared/llm/index.js");
94
- return createLLMClient(model);
95
- });
96
- }
97
- export {
98
- LIBRETTO_CONFIG_DIR,
99
- LIBRETTO_CONFIG_PATH,
100
- LIBRETTO_GITIGNORE_PATH,
101
- LIBRETTO_SESSIONS_DIR,
102
- PROFILES_DIR,
103
- REPO_ROOT,
104
- closeLogger,
105
- createLoggerForSession,
106
- ensureLibrettoSetup,
107
- getLLMClientFactory,
108
- getSessionActionsLogPath,
109
- getSessionDir,
110
- getSessionLogsPath,
111
- getSessionNetworkLogPath,
112
- getSessionSnapshotRunDir,
113
- getSessionSnapshotsDir,
114
- getSessionStatePath,
115
- maybeConfigureLLMClientFactoryFromEnv,
116
- setLLMClientFactory,
117
- withSessionLogger
118
- };
@@ -1,29 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { unlink } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { getSessionDir } from "./context.js";
5
- function getPauseSignalPaths(session) {
6
- const sessionDir = getSessionDir(session);
7
- return {
8
- pausedSignalPath: join(sessionDir, `${session}.paused`),
9
- resumeSignalPath: join(sessionDir, `${session}.resume`),
10
- completedSignalPath: join(sessionDir, `${session}.completed`),
11
- failedSignalPath: join(sessionDir, `${session}.failed`),
12
- outputSignalPath: join(sessionDir, `${session}.output`)
13
- };
14
- }
15
- async function removeSignalIfExists(path) {
16
- if (!existsSync(path)) return;
17
- try {
18
- await unlink(path);
19
- } catch (error) {
20
- const code = error.code;
21
- if (code !== "ENOENT") {
22
- throw error;
23
- }
24
- }
25
- }
26
- export {
27
- getPauseSignalPaths,
28
- removeSignalIfExists
29
- };
@@ -1,491 +0,0 @@
1
- async function installSessionTelemetry(options) {
2
- const STATIC_EXT_RE = /\.(css|js|png|jpg|jpeg|gif|woff|woff2|ttf|ico|svg)(\?|$)/i;
3
- const { context, initialPage, logAction, logNetwork } = options;
4
- const includeUserDomActions = options.includeUserDomActions ?? false;
5
- const pageIdCache = /* @__PURE__ */ new WeakMap();
6
- const wrappedPages = /* @__PURE__ */ new WeakSet();
7
- const exposedPages = /* @__PURE__ */ new WeakSet();
8
- const resolvePageId = async (page) => {
9
- if (pageIdCache.has(page)) return pageIdCache.get(page);
10
- const cdpSession = await context.newCDPSession(page);
11
- try {
12
- const targetInfo = await cdpSession.send("Target.getTargetInfo");
13
- const targetId = targetInfo?.targetInfo?.targetId;
14
- if (typeof targetId !== "string" || targetId.length === 0) {
15
- throw new Error(`Could not resolve target id for page at URL "${page.url()}".`);
16
- }
17
- pageIdCache.set(page, targetId);
18
- return targetId;
19
- } finally {
20
- await cdpSession.detach();
21
- }
22
- };
23
- const emitAction = (entry) => {
24
- logAction({
25
- ts: (/* @__PURE__ */ new Date()).toISOString(),
26
- ...entry
27
- });
28
- };
29
- const emitNetwork = (entry) => {
30
- logNetwork({
31
- ts: (/* @__PURE__ */ new Date()).toISOString(),
32
- ...entry
33
- });
34
- };
35
- const markApiActionInProgress = async (page, inProgress) => {
36
- await page.evaluate((flag) => {
37
- window.__btApiActionInProgress = flag;
38
- }, inProgress);
39
- };
40
- const wrapLocator = (locator, page, pageId) => {
41
- if (locator.__librettoActionLogged) return locator;
42
- locator.__librettoActionLogged = true;
43
- const locatorActionMethods = [
44
- "click",
45
- "dblclick",
46
- "fill",
47
- "type",
48
- "press",
49
- "check",
50
- "uncheck",
51
- "selectOption",
52
- "hover",
53
- "focus",
54
- "scrollIntoViewIfNeeded",
55
- "waitFor",
56
- "innerHTML",
57
- "innerText",
58
- "textContent",
59
- "inputValue",
60
- "isChecked",
61
- "isDisabled",
62
- "isEditable",
63
- "isEnabled",
64
- "isHidden",
65
- "isVisible",
66
- "count",
67
- "boundingBox",
68
- "screenshot",
69
- "evaluate",
70
- "evaluateAll",
71
- "evaluateHandle",
72
- "getAttribute",
73
- "dispatchEvent",
74
- "setInputFiles",
75
- "selectText",
76
- "dragTo",
77
- "highlight",
78
- "tap"
79
- ];
80
- const locatorReturningMethods = [
81
- "first",
82
- "last",
83
- "locator",
84
- "getByRole",
85
- "getByText",
86
- "getByLabel",
87
- "getByPlaceholder",
88
- "getByAltText",
89
- "getByTitle",
90
- "getByTestId",
91
- "filter",
92
- "and",
93
- "or"
94
- ];
95
- for (const actMethod of locatorActionMethods) {
96
- if (typeof locator[actMethod] !== "function") continue;
97
- const originalAction = locator[actMethod].bind(locator);
98
- locator[actMethod] = async (...actionArgs) => {
99
- const start = Date.now();
100
- await markApiActionInProgress(page, true);
101
- try {
102
- const result = await originalAction(...actionArgs);
103
- emitAction({
104
- pageId,
105
- action: actMethod,
106
- source: "agent",
107
- selector: "locator",
108
- value: actionArgs[0] !== void 0 ? String(actionArgs[0]).slice(0, 100) : void 0,
109
- duration: Date.now() - start,
110
- success: true
111
- });
112
- return result;
113
- } catch (error) {
114
- emitAction({
115
- pageId,
116
- action: actMethod,
117
- source: "agent",
118
- selector: "locator",
119
- duration: Date.now() - start,
120
- success: false,
121
- error: error?.message ?? String(error)
122
- });
123
- throw error;
124
- } finally {
125
- await markApiActionInProgress(page, false);
126
- }
127
- };
128
- }
129
- for (const method of locatorReturningMethods) {
130
- if (typeof locator[method] !== "function") continue;
131
- const originalMethod = locator[method].bind(locator);
132
- locator[method] = (...args) => {
133
- const child = originalMethod(...args);
134
- return wrapLocator(child, page, pageId);
135
- };
136
- }
137
- if (typeof locator.nth === "function") {
138
- const originalNth = locator.nth.bind(locator);
139
- locator.nth = (index) => {
140
- const child = originalNth(index);
141
- return wrapLocator(child, page, pageId);
142
- };
143
- }
144
- if (typeof locator.all === "function") {
145
- const originalAll = locator.all.bind(locator);
146
- locator.all = async () => {
147
- const items = await originalAll();
148
- return items.map((item) => wrapLocator(item, page, pageId));
149
- };
150
- }
151
- return locator;
152
- };
153
- const installUserDomTracking = async (page, pageId) => {
154
- if (exposedPages.has(page)) return;
155
- exposedPages.add(page);
156
- await page.exposeFunction("__btActionLog", (jsonStr) => {
157
- const parsed = JSON.parse(jsonStr);
158
- emitAction({
159
- pageId,
160
- source: "user",
161
- ...parsed
162
- });
163
- });
164
- await page.addInitScript(() => {
165
- if (window.__btDomListenersInstalled) return;
166
- window.__btDomListenersInstalled = true;
167
- const identify = (el) => {
168
- if (!el || !el.tagName) return "";
169
- const testId = el.getAttribute("data-testid");
170
- if (testId) return `[data-testid="${testId}"]`;
171
- const role = el.getAttribute("role") || "";
172
- const id = el.id;
173
- if (role && id) return `${role}#${id}`;
174
- const label = el.getAttribute("aria-label") || (el.textContent || "").trim().slice(0, 30) || "";
175
- if (role && label) return `${role} "${label}"`;
176
- const tag = el.tagName.toLowerCase();
177
- const cls = el.className && typeof el.className === "string" ? "." + el.className.trim().split(/\s+/).slice(0, 2).join(".") : "";
178
- return `${tag}${cls}`;
179
- };
180
- let clickTimer = null;
181
- let pendingClick = null;
182
- document.addEventListener(
183
- "click",
184
- (event) => {
185
- if (window.__btApiActionInProgress) return;
186
- const target = event.target;
187
- const selector = identify(target);
188
- if (target?.type === "checkbox") {
189
- window.__btActionLog(
190
- JSON.stringify({
191
- action: target.checked ? "check" : "uncheck",
192
- selector,
193
- success: true
194
- })
195
- );
196
- return;
197
- }
198
- pendingClick = { selector };
199
- if (clickTimer) clearTimeout(clickTimer);
200
- clickTimer = setTimeout(() => {
201
- if (pendingClick) {
202
- window.__btActionLog(
203
- JSON.stringify({
204
- action: "click",
205
- selector: pendingClick.selector,
206
- success: true
207
- })
208
- );
209
- }
210
- pendingClick = null;
211
- clickTimer = null;
212
- }, 200);
213
- },
214
- true
215
- );
216
- document.addEventListener(
217
- "dblclick",
218
- (event) => {
219
- if (window.__btApiActionInProgress) return;
220
- if (clickTimer) {
221
- clearTimeout(clickTimer);
222
- clickTimer = null;
223
- pendingClick = null;
224
- }
225
- const selector = identify(event.target);
226
- window.__btActionLog(
227
- JSON.stringify({ action: "dblclick", selector, success: true })
228
- );
229
- },
230
- true
231
- );
232
- const inputTimers = /* @__PURE__ */ new WeakMap();
233
- document.addEventListener(
234
- "input",
235
- (event) => {
236
- if (window.__btApiActionInProgress) return;
237
- const target = event.target;
238
- const selector = identify(target);
239
- if (target.tagName === "SELECT") {
240
- window.__btActionLog(
241
- JSON.stringify({
242
- action: "selectOption",
243
- selector,
244
- value: target.value,
245
- success: true
246
- })
247
- );
248
- return;
249
- }
250
- const existing = inputTimers.get(target);
251
- if (existing) clearTimeout(existing);
252
- inputTimers.set(
253
- target,
254
- setTimeout(() => {
255
- inputTimers.delete(target);
256
- window.__btActionLog(
257
- JSON.stringify({
258
- action: "fill",
259
- selector,
260
- value: (target.value || "").slice(0, 100),
261
- success: true
262
- })
263
- );
264
- }, 500)
265
- );
266
- },
267
- true
268
- );
269
- const specialKeys = /* @__PURE__ */ new Set([
270
- "Enter",
271
- "Escape",
272
- "Tab",
273
- "Backspace",
274
- "Delete",
275
- "ArrowUp",
276
- "ArrowDown",
277
- "ArrowLeft",
278
- "ArrowRight",
279
- "Home",
280
- "End",
281
- "PageUp",
282
- "PageDown",
283
- "F1",
284
- "F2",
285
- "F3",
286
- "F4",
287
- "F5",
288
- "F6",
289
- "F7",
290
- "F8",
291
- "F9",
292
- "F10",
293
- "F11",
294
- "F12"
295
- ]);
296
- document.addEventListener(
297
- "keydown",
298
- (event) => {
299
- if (window.__btApiActionInProgress) return;
300
- const isShortcut = event.ctrlKey || event.metaKey || event.altKey;
301
- if (!isShortcut && !specialKeys.has(event.key)) return;
302
- const selector = identify(event.target);
303
- const keyDesc = (event.ctrlKey ? "Ctrl+" : "") + (event.metaKey ? "Meta+" : "") + (event.altKey ? "Alt+" : "") + (event.shiftKey ? "Shift+" : "") + event.key;
304
- window.__btActionLog(
305
- JSON.stringify({
306
- action: "press",
307
- selector,
308
- value: keyDesc,
309
- success: true
310
- })
311
- );
312
- },
313
- true
314
- );
315
- let scrollTimer = null;
316
- document.addEventListener(
317
- "scroll",
318
- () => {
319
- if (window.__btApiActionInProgress) return;
320
- if (scrollTimer) clearTimeout(scrollTimer);
321
- scrollTimer = setTimeout(() => {
322
- scrollTimer = null;
323
- window.__btActionLog(
324
- JSON.stringify({
325
- action: "scroll",
326
- selector: "document",
327
- value: `y=${window.scrollY}`,
328
- success: true
329
- })
330
- );
331
- }, 300);
332
- },
333
- true
334
- );
335
- });
336
- };
337
- const wrapPageActions = (page, pageId) => {
338
- if (wrappedPages.has(page)) return;
339
- wrappedPages.add(page);
340
- const pageActions = [
341
- "click",
342
- "dblclick",
343
- "fill",
344
- "type",
345
- "press",
346
- "check",
347
- "uncheck",
348
- "selectOption",
349
- "hover",
350
- "focus"
351
- ];
352
- const navActions = ["goto", "reload", "goBack", "goForward"];
353
- const locatorFactories = [
354
- "locator",
355
- "getByRole",
356
- "getByText",
357
- "getByLabel",
358
- "getByPlaceholder",
359
- "getByAltText",
360
- "getByTitle",
361
- "getByTestId"
362
- ];
363
- for (const method of pageActions) {
364
- const originalMethod = page[method].bind(page);
365
- page[method] = async (...args) => {
366
- const start = Date.now();
367
- await markApiActionInProgress(page, true);
368
- try {
369
- const result = await originalMethod(...args);
370
- emitAction({
371
- pageId,
372
- action: method,
373
- source: "agent",
374
- selector: typeof args[0] === "string" ? args[0] : void 0,
375
- value: args[1] !== void 0 ? String(args[1]).slice(0, 100) : void 0,
376
- duration: Date.now() - start,
377
- success: true
378
- });
379
- return result;
380
- } catch (error) {
381
- emitAction({
382
- pageId,
383
- action: method,
384
- source: "agent",
385
- selector: typeof args[0] === "string" ? args[0] : void 0,
386
- duration: Date.now() - start,
387
- success: false,
388
- error: error?.message ?? String(error)
389
- });
390
- throw error;
391
- } finally {
392
- await markApiActionInProgress(page, false);
393
- }
394
- };
395
- }
396
- for (const method of navActions) {
397
- const originalMethod = page[method].bind(page);
398
- page[method] = async (...args) => {
399
- const start = Date.now();
400
- try {
401
- const result = await originalMethod(...args);
402
- emitAction({
403
- pageId,
404
- action: method,
405
- source: "agent",
406
- url: typeof args[0] === "string" ? args[0] : page.url(),
407
- duration: Date.now() - start,
408
- success: true
409
- });
410
- return result;
411
- } catch (error) {
412
- emitAction({
413
- pageId,
414
- action: method,
415
- source: "agent",
416
- url: typeof args[0] === "string" ? args[0] : void 0,
417
- duration: Date.now() - start,
418
- success: false,
419
- error: error?.message ?? String(error)
420
- });
421
- throw error;
422
- }
423
- };
424
- }
425
- for (const factory of locatorFactories) {
426
- const originalFactory = page[factory].bind(page);
427
- page[factory] = (...factoryArgs) => {
428
- const locator = originalFactory(...factoryArgs);
429
- return wrapLocator(locator, page, pageId);
430
- };
431
- }
432
- };
433
- const installForPage = async (page) => {
434
- const pageId = await resolvePageId(page);
435
- wrapPageActions(page, pageId);
436
- if (includeUserDomActions) {
437
- await installUserDomTracking(page, pageId);
438
- }
439
- page.on("response", async (response) => {
440
- const request = response.request();
441
- const url = request.url();
442
- if (STATIC_EXT_RE.test(url) || url.startsWith("chrome-extension://")) return;
443
- emitNetwork({
444
- pageId,
445
- method: request.method(),
446
- url,
447
- status: response.status(),
448
- contentType: response.headers()["content-type"] ?? null,
449
- postData: request.method() === "POST" || request.method() === "PUT" || request.method() === "PATCH" ? (request.postData() ?? "").substring(0, 2e3) : void 0,
450
- responseBody: null,
451
- size: null,
452
- durationMs: null
453
- });
454
- });
455
- page.on("framenavigated", (frame) => {
456
- if (frame !== page.mainFrame()) return;
457
- emitAction({
458
- pageId,
459
- action: "navigate",
460
- source: "agent",
461
- url: frame.url(),
462
- success: true
463
- });
464
- });
465
- page.on("popup", (popup) => {
466
- emitAction({
467
- pageId,
468
- action: "popup",
469
- source: "agent",
470
- url: popup.url(),
471
- success: true
472
- });
473
- });
474
- page.on("dialog", (dialog) => {
475
- emitAction({
476
- pageId,
477
- action: "dialog",
478
- source: "agent",
479
- value: `${dialog.type()}: ${dialog.message().slice(0, 500)}`,
480
- success: true
481
- });
482
- });
483
- };
484
- await installForPage(initialPage);
485
- context.on("page", (newPage) => {
486
- void installForPage(newPage);
487
- });
488
- }
489
- export {
490
- installSessionTelemetry
491
- };