@skyramp/mcp 0.2.1 → 0.2.3

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.
@@ -0,0 +1,359 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var loadTraceTool_exports = {};
20
+ __export(loadTraceTool_exports, {
21
+ decodeModifiers: () => decodeModifiers,
22
+ describeStep: () => describeStep,
23
+ describeStopReason: () => describeStopReason,
24
+ listStepsFrom: () => listStepsFrom,
25
+ loadTraceMcpTool: () => loadTraceMcpTool,
26
+ loadTraceSchema: () => loadTraceSchema,
27
+ replayActions: () => replayActions,
28
+ urlMatchesPattern: () => urlMatchesPattern
29
+ });
30
+ module.exports = __toCommonJS(loadTraceTool_exports);
31
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
32
+ var import_utils = require("playwright-core/lib/utils");
33
+ var import_tool = require("../sdk/tool");
34
+ var import_mouseActions = require("./common/mouseActions");
35
+ const loadTraceSchema = {
36
+ name: "skyramp_load_trace",
37
+ title: "Load and replay a Skyramp trace",
38
+ description: [
39
+ "Load a previously recorded Skyramp trace (.zip or .jsonl/.txt) and replay its actions against the live browser to restore state, then continue recording from that point.",
40
+ "The replayed actions are merged into the current recording, so subsequent browser_* steps append to them and skyramp_export_zip writes a combined trace.",
41
+ "STOPPING EARLY: when the user wants to stop partway through the loaded trace before continuing, set ONE of stopAtStep / stopAtUrl / stopBefore based on their prompt. Omit all three to replay the whole trace.",
42
+ "- stopAtStep: replay steps 1..N then stop (N is 1-based, from the numbered step list).",
43
+ "- stopAtUrl: stop once the active page URL matches this glob/regex/substring (checked after each action).",
44
+ '- stopBefore: stop right BEFORE the first action whose description contains this text (case-insensitive), e.g. "Checkout" to stop before clicking Checkout.',
45
+ "If unsure where to stop, first call with dryRun:true to read the numbered step list, then call again with the chosen stop parameter."
46
+ ].join(" "),
47
+ inputSchema: import_mcpBundle.z.object({
48
+ path: import_mcpBundle.z.string().describe("Absolute path to the trace file (.zip, .jsonl, or .txt)."),
49
+ stopAtStep: import_mcpBundle.z.number().int().positive().optional().describe("Replay steps 1..N (1-based), then stop before continuing."),
50
+ stopAtUrl: import_mcpBundle.z.string().optional().describe("Stop once the active page URL matches this glob/regex/substring."),
51
+ stopBefore: import_mcpBundle.z.string().optional().describe("Stop before the first action whose description contains this text (case-insensitive)."),
52
+ dryRun: import_mcpBundle.z.boolean().optional().describe("Parse and list the steps WITHOUT replaying. Use to choose a stop point."),
53
+ speed: import_mcpBundle.z.enum(["fast", "slow"]).optional().describe('Replay speed. "slow" adds a 1s delay between actions (default "fast").')
54
+ }),
55
+ // Replaying drives the live browser and mutates the recording, so this is an
56
+ // action tool (readOnlyHint:false / destructiveHint:true), not readOnly.
57
+ type: "action"
58
+ };
59
+ function loadTraceMcpTool() {
60
+ return (0, import_tool.toMcpTool)(loadTraceSchema);
61
+ }
62
+ function decodeModifiers(mask) {
63
+ if (!mask)
64
+ return [];
65
+ const out = [];
66
+ if (mask & 1) out.push("Alt");
67
+ if ((mask & 6) === 6) {
68
+ out.push("ControlOrMeta");
69
+ } else {
70
+ if (mask & 2) out.push("Control");
71
+ if (mask & 4) out.push("Meta");
72
+ }
73
+ if (mask & 8) out.push("Shift");
74
+ return out;
75
+ }
76
+ const METADATA_ONLY_ACTIONS = /* @__PURE__ */ new Set([
77
+ "marker",
78
+ "comment",
79
+ "beginBlock",
80
+ "endBlock",
81
+ "openPage",
82
+ "closePage",
83
+ "modalOpen",
84
+ "modalClose",
85
+ "iframeLoad",
86
+ "visualSnapshot",
87
+ "tableSnapshot",
88
+ "domSnapshot",
89
+ "selectArea",
90
+ "penTool",
91
+ "assertApiRequest"
92
+ ]);
93
+ function describeStep(action, index) {
94
+ const a = action.action;
95
+ const onPage = action.frame.pageAlias && action.frame.pageAlias !== "page" ? ` [${action.frame.pageAlias}]` : "";
96
+ let detail = "";
97
+ if (a.name === "navigate")
98
+ detail = a.url;
99
+ else if (a.selector)
100
+ detail = (0, import_utils.asLocator)("javascript", a.selector);
101
+ if ((a.name === "fill" || a.name === "assertText") && a.text !== void 0)
102
+ detail += ` = ${JSON.stringify(a.text)}`;
103
+ else if (a.name === "assertValue" && a.value !== void 0)
104
+ detail += ` = ${JSON.stringify(a.value)}`;
105
+ else if (a.name === "press" && a.key !== void 0)
106
+ detail += ` ${a.key}`;
107
+ return `#${index + 1} ${a.name}${onPage}${detail ? ` ${detail}` : ""}`;
108
+ }
109
+ function listStepsFrom(allActions, fromIndex) {
110
+ if (fromIndex >= allActions.length)
111
+ return "(none remaining)";
112
+ return allActions.slice(fromIndex).map((a, i) => describeStep(a, fromIndex + i)).join("\n");
113
+ }
114
+ const ENTER_FRAME = " >> internal:control=enter-frame >> ";
115
+ function buildFullSelector(framePath, selector) {
116
+ return [...framePath ?? [], selector].join(ENTER_FRAME);
117
+ }
118
+ function describeStopReason(result) {
119
+ switch (result.stopReason) {
120
+ case "done":
121
+ return "Reached the end of the trace.";
122
+ case "stopAtStep":
123
+ return `Stopped at the requested step (${result.completedCount}).`;
124
+ case "stopAtUrl":
125
+ return "Stopped because the active page URL matched the requested pattern.";
126
+ case "stopBefore":
127
+ return "Stopped just before the requested action.";
128
+ case "error":
129
+ return "Stopped because an action failed.";
130
+ }
131
+ }
132
+ async function replayActions(actionsList, callbacks, params) {
133
+ const delay = params.speed === "slow" ? 1e3 : 0;
134
+ const stopBefore = params.stopBefore?.toLowerCase();
135
+ let completedCount = 0;
136
+ for (let i = 0; i < actionsList.length; i++) {
137
+ const action = actionsList[i];
138
+ if (stopBefore && describeStep(action, i).toLowerCase().includes(stopBefore))
139
+ return { completedCount, stopIndex: i, stopReason: "stopBefore" };
140
+ const alias = action.frame.pageAlias || "page";
141
+ const page = callbacks.pageForAlias(alias);
142
+ if (!METADATA_ONLY_ACTIONS.has(action.action.name)) {
143
+ if (!page) {
144
+ return {
145
+ completedCount,
146
+ stopIndex: i,
147
+ stopReason: "error",
148
+ error: { message: `No live page for alias "${alias}"`, actionName: action.action.name, stepIndex: i + 1 }
149
+ };
150
+ }
151
+ try {
152
+ await performClientAction(page, action);
153
+ } catch (e) {
154
+ return {
155
+ completedCount,
156
+ stopIndex: i,
157
+ stopReason: "error",
158
+ error: { message: e.message, actionName: action.action.name, stepIndex: i + 1 }
159
+ };
160
+ }
161
+ }
162
+ completedCount = i + 1;
163
+ if (params.stopAtStep !== void 0 && completedCount >= params.stopAtStep)
164
+ return { completedCount, stopIndex: i + 1, stopReason: "stopAtStep" };
165
+ if (params.stopAtUrl) {
166
+ const currentUrl = page?.url() ?? "";
167
+ if (urlMatchesPattern(currentUrl, params.stopAtUrl))
168
+ return { completedCount, stopIndex: i + 1, stopReason: "stopAtUrl" };
169
+ }
170
+ if (delay)
171
+ await new Promise((resolve) => setTimeout(resolve, delay));
172
+ }
173
+ return { completedCount, stopIndex: actionsList.length, stopReason: "done" };
174
+ }
175
+ function urlMatchesPattern(currentUrl, pattern) {
176
+ const regexLiteral = /^\/(.*)\/([a-z]*)$/i.exec(pattern);
177
+ if (regexLiteral) {
178
+ try {
179
+ return new RegExp(regexLiteral[1], regexLiteral[2]).test(currentUrl);
180
+ } catch {
181
+ }
182
+ }
183
+ if (/[*{]/.test(pattern))
184
+ return (0, import_utils.urlMatches)(void 0, currentUrl, pattern);
185
+ return currentUrl.toLowerCase().includes(pattern.toLowerCase());
186
+ }
187
+ async function withMouseModifiers(page, mask, fn) {
188
+ const keys = (0, import_mouseActions.decodeModifierKeys)(mask);
189
+ for (const k of keys)
190
+ await page.keyboard.down(k);
191
+ try {
192
+ await fn();
193
+ } finally {
194
+ for (const k of [...keys].reverse())
195
+ await page.keyboard.up(k);
196
+ }
197
+ }
198
+ const DEFAULT_ACTION_TIMEOUT = 15e3;
199
+ async function performClientAction(page, actionInContext) {
200
+ const action = actionInContext.action;
201
+ const opts = { timeout: DEFAULT_ACTION_TIMEOUT };
202
+ if (action.name === "navigate") {
203
+ await page.goto(action.url, { ...opts, waitUntil: "domcontentloaded" });
204
+ return;
205
+ }
206
+ if (action.name === "waitForTimeout") {
207
+ await new Promise((resolve) => setTimeout(resolve, action.duration ?? 0));
208
+ return;
209
+ }
210
+ if (action.name === "waitForSelector") {
211
+ const state = action.state === "hidden" ? "hidden" : "visible";
212
+ const waitSelector = buildFullSelector(actionInContext.frame.framePath, action.selector);
213
+ await page.locator(waitSelector).first().waitFor({ state, ...opts }).catch(() => {
214
+ });
215
+ return;
216
+ }
217
+ if (action.name === "dragAndDrop" || action.name === "dragTo") {
218
+ const fp = actionInContext.frame.framePath;
219
+ const sourceSel = buildFullSelector(fp, action.source ?? action.selector);
220
+ const targetSel = buildFullSelector(fp, action.target ?? action.targetSelector);
221
+ await page.locator(sourceSel).dragTo(page.locator(targetSel), opts);
222
+ return;
223
+ }
224
+ if (action.name === "press" && !action.selector) {
225
+ const modifiers = decodeModifiers(action.modifiers);
226
+ const shortcut = [...modifiers, action.key].join("+");
227
+ await page.keyboard.press(shortcut);
228
+ return;
229
+ }
230
+ if (action.name === "mouse.move") {
231
+ if (!action.position)
232
+ return;
233
+ if (action.steps !== void 0)
234
+ await page.mouse.move(action.position.x, action.position.y, { steps: action.steps });
235
+ else
236
+ await page.mouse.move(action.position.x, action.position.y);
237
+ return;
238
+ }
239
+ if (action.name === "mouse.down") {
240
+ if (action.button && action.button !== "left")
241
+ await page.mouse.down({ button: action.button });
242
+ else
243
+ await page.mouse.down();
244
+ return;
245
+ }
246
+ if (action.name === "mouse.up") {
247
+ if (action.button && action.button !== "left")
248
+ await page.mouse.up({ button: action.button });
249
+ else
250
+ await page.mouse.up();
251
+ return;
252
+ }
253
+ if (action.name === "mouse.wheel") {
254
+ await withMouseModifiers(page, action.modifiers, () => page.mouse.wheel(action.deltaX ?? 0, action.deltaY ?? 0));
255
+ return;
256
+ }
257
+ if (action.name === "click" && action.position && (!action.selector || action.selector === "body")) {
258
+ const button = action.button ?? "left";
259
+ const clickCount = action.clickCount ?? 1;
260
+ const needsOpts = button !== "left" || clickCount !== 1;
261
+ await withMouseModifiers(page, action.modifiers, () => needsOpts ? page.mouse.click(action.position.x, action.position.y, { button, clickCount }) : page.mouse.click(action.position.x, action.position.y));
262
+ return;
263
+ }
264
+ if (!action.selector)
265
+ return;
266
+ const selector = buildFullSelector(actionInContext.frame.framePath, action.selector);
267
+ const locator = page.locator(selector);
268
+ switch (action.name) {
269
+ case "click": {
270
+ const clickOpts = { ...opts };
271
+ if (action.button && action.button !== "left")
272
+ clickOpts.button = action.button;
273
+ if (action.clickCount && action.clickCount > 1)
274
+ clickOpts.clickCount = action.clickCount;
275
+ if (action.position)
276
+ clickOpts.position = action.position;
277
+ const modifiers = decodeModifiers(action.modifiers);
278
+ if (modifiers.length)
279
+ clickOpts.modifiers = modifiers;
280
+ await locator.click(clickOpts);
281
+ return;
282
+ }
283
+ case "hover":
284
+ await locator.hover({ ...opts, ...action.position ? { position: action.position } : {} });
285
+ return;
286
+ case "fill":
287
+ await locator.fill(action.text ?? "", opts);
288
+ return;
289
+ case "pressSequentially":
290
+ await locator.pressSequentially(action.text ?? "", opts);
291
+ return;
292
+ case "press": {
293
+ const modifiers = decodeModifiers(action.modifiers);
294
+ const shortcut = [...modifiers, action.key].join("+");
295
+ await locator.press(shortcut, opts);
296
+ return;
297
+ }
298
+ case "check":
299
+ await locator.check(opts);
300
+ return;
301
+ case "uncheck":
302
+ await locator.uncheck(opts);
303
+ return;
304
+ case "select":
305
+ await locator.selectOption(action.options ?? [], opts);
306
+ return;
307
+ case "setInputFiles":
308
+ await locator.setInputFiles(action.files ?? [], opts);
309
+ return;
310
+ case "fileChooser": {
311
+ const fileChooserPromise = page.waitForEvent("filechooser");
312
+ await locator.click(opts);
313
+ const fileChooser = await fileChooserPromise;
314
+ await fileChooser.setFiles(action.files ?? []);
315
+ return;
316
+ }
317
+ // Assertions: re-run against the live page so a drifted trace fails loudly
318
+ // (faithful to the manual recorder's replay).
319
+ case "assertText": {
320
+ const actual = await locator.textContent(opts) ?? "";
321
+ const substring = action.substring !== false;
322
+ const ok = substring ? actual.includes(action.text) : actual.trim() === String(action.text).trim();
323
+ if (!ok)
324
+ throw new Error(`assertText failed: expected text to ${substring ? "contain" : "equal"} ${JSON.stringify(action.text)}, got ${JSON.stringify(actual)}`);
325
+ return;
326
+ }
327
+ case "assertValue": {
328
+ const actual = await locator.inputValue(opts);
329
+ if (actual !== action.value)
330
+ throw new Error(`assertValue failed: expected ${JSON.stringify(action.value)}, got ${JSON.stringify(actual)}`);
331
+ return;
332
+ }
333
+ case "assertChecked": {
334
+ const checked = await locator.isChecked(opts);
335
+ if (checked !== !!action.checked)
336
+ throw new Error(`assertChecked failed: expected checked=${!!action.checked}, got ${checked}`);
337
+ return;
338
+ }
339
+ case "assertVisible": {
340
+ const visible = await locator.isVisible(opts);
341
+ if (!visible)
342
+ throw new Error(`assertVisible failed: element is not visible`);
343
+ return;
344
+ }
345
+ default:
346
+ return;
347
+ }
348
+ }
349
+ // Annotate the CommonJS export names for ESM import in node:
350
+ 0 && (module.exports = {
351
+ decodeModifiers,
352
+ describeStep,
353
+ describeStopReason,
354
+ listStepsFrom,
355
+ loadTraceMcpTool,
356
+ loadTraceSchema,
357
+ replayActions,
358
+ urlMatchesPattern
359
+ });
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var mouseActionTool_exports = {};
20
+ __export(mouseActionTool_exports, {
21
+ _schema: () => mouseActionSchema,
22
+ executeMouseAction: () => executeMouseAction,
23
+ mouseActionMcpTool: () => mouseActionMcpTool,
24
+ mouseActionSchema: () => mouseActionSchema
25
+ });
26
+ module.exports = __toCommonJS(mouseActionTool_exports);
27
+ var import_mcpBundle = require("playwright-core/lib/mcpBundle");
28
+ var import_tool = require("../sdk/tool");
29
+ var import_mouseActions = require("./common/mouseActions");
30
+ const mouseActionSchema = {
31
+ name: "browser_mouse_action",
32
+ title: "Mouse action (coordinate-based)",
33
+ description: [
34
+ "Perform coordinate-based mouse interactions: drag-and-drop, slider adjustment, canvas/diagram manipulation, scrolling, and other gestures that operate on viewport pixel positions rather than element references.",
35
+ "Primary uses: drag an item between positions (drag), move a slider thumb (drag), pan/draw on a canvas (move/down/up), and scroll a region (wheel).",
36
+ "The `action` parameter selects the gesture:",
37
+ "- drag: press at (x, y), move to (endX, endY), release. Decomposed into low-level mouse events (move\u2192down\u2192move\u2192up) so it works for sliders, canvas, and custom drag-handles where high-level element drag fails.",
38
+ "- move / down / up: individual pointer steps for composing custom gestures.",
39
+ "- wheel: scroll by deltaX / deltaY at the pointer position.",
40
+ '- click: a single position click at (x, y). Use for canvas hotspots, or as a fallback for an interactive element that has no usable accessibility ref or is occluded by an overlay (where browser_click reports "intercepts pointer events"). For ordinary elements, prefer browser_click.',
41
+ "Coordinates are viewport pixels, obtained from a snapshot or screenshot."
42
+ ].join(" "),
43
+ inputSchema: import_mcpBundle.z.object({
44
+ action: import_mcpBundle.z.enum(["move", "down", "up", "click", "wheel", "drag"]).describe("The mouse action to perform."),
45
+ x: import_mcpBundle.z.number().optional().describe("X coordinate (viewport px). Required for move/click/wheel; the start X for drag."),
46
+ y: import_mcpBundle.z.number().optional().describe("Y coordinate (viewport px). Required for move/click/wheel; the start Y for drag."),
47
+ endX: import_mcpBundle.z.number().optional().describe("End X coordinate for drag."),
48
+ endY: import_mcpBundle.z.number().optional().describe("End Y coordinate for drag."),
49
+ button: import_mcpBundle.z.enum(["left", "right", "middle"]).optional().describe("Mouse button for down/up/click. Defaults to left."),
50
+ clickCount: import_mcpBundle.z.number().int().positive().optional().describe("Number of clicks for click (e.g. 2 for double-click). Defaults to 1."),
51
+ deltaX: import_mcpBundle.z.number().optional().describe("Horizontal scroll delta for wheel."),
52
+ deltaY: import_mcpBundle.z.number().optional().describe("Vertical scroll delta for wheel."),
53
+ steps: import_mcpBundle.z.number().int().positive().optional().describe("Intermediate move steps for move/drag (smoother movement)."),
54
+ modifiers: import_mcpBundle.z.number().int().min(0).max(15).optional().describe("Modifier bitmask (Alt=1, Control=2, Meta=4, Shift=8) for click/wheel. Range 0-15.")
55
+ }),
56
+ type: "action"
57
+ };
58
+ function mouseActionMcpTool() {
59
+ return (0, import_tool.toMcpTool)(mouseActionSchema);
60
+ }
61
+ async function executeMouseAction(page, params) {
62
+ const built = (0, import_mouseActions.mouseActionToJsonl)(params);
63
+ if ("error" in built)
64
+ return { result: { content: [{ type: "text", text: `### Error
65
+ ${built.error}` }], isError: true }, actions: [] };
66
+ if (!page)
67
+ return { result: { content: [{ type: "text", text: "### Error\nNo open page. Call browser_navigate first." }], isError: true }, actions: [] };
68
+ const code = [];
69
+ try {
70
+ for (const a of built.actions) {
71
+ code.push(...(0, import_mouseActions.mouseJsonlToCode)(a));
72
+ await runOne(page, a);
73
+ }
74
+ } catch (e) {
75
+ return { result: { content: [{ type: "text", text: `### Error
76
+ Mouse action failed: ${e.message}` }], isError: true }, actions: [] };
77
+ }
78
+ return {
79
+ result: { content: [{ type: "text", text: `### Ran Playwright code
80
+ ${code.join("\n")}` }] },
81
+ actions: built.actions
82
+ };
83
+ }
84
+ async function runOne(page, a) {
85
+ switch (a.name) {
86
+ case "mouse.move":
87
+ if (a.steps !== void 0)
88
+ await page.mouse.move(a.position.x, a.position.y, { steps: a.steps });
89
+ else
90
+ await page.mouse.move(a.position.x, a.position.y);
91
+ return;
92
+ case "mouse.down":
93
+ if (a.button && a.button !== "left")
94
+ await page.mouse.down({ button: a.button });
95
+ else
96
+ await page.mouse.down();
97
+ return;
98
+ case "mouse.up":
99
+ if (a.button && a.button !== "left")
100
+ await page.mouse.up({ button: a.button });
101
+ else
102
+ await page.mouse.up();
103
+ return;
104
+ case "mouse.wheel":
105
+ await withModifiers(page, a.modifiers, () => page.mouse.wheel(a.deltaX, a.deltaY));
106
+ return;
107
+ case "click": {
108
+ const needsOpts = a.button !== "left" || a.clickCount !== 1;
109
+ await withModifiers(page, a.modifiers, () => needsOpts ? page.mouse.click(a.position.x, a.position.y, { button: a.button, clickCount: a.clickCount }) : page.mouse.click(a.position.x, a.position.y));
110
+ return;
111
+ }
112
+ }
113
+ }
114
+ async function withModifiers(page, mask, fn) {
115
+ const keys = (0, import_mouseActions.decodeModifierKeys)(mask);
116
+ for (const k of keys)
117
+ await page.keyboard.down(k);
118
+ try {
119
+ await fn();
120
+ } finally {
121
+ for (const k of [...keys].reverse())
122
+ await page.keyboard.up(k);
123
+ }
124
+ }
125
+ // Annotate the CommonJS export names for ESM import in node:
126
+ 0 && (module.exports = {
127
+ _schema,
128
+ executeMouseAction,
129
+ mouseActionMcpTool,
130
+ mouseActionSchema
131
+ });
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var skyRampImport_exports = {};
30
+ __export(skyRampImport_exports, {
31
+ actionsFromFile: () => actionsFromFile,
32
+ actionsFromPath: () => actionsFromPath,
33
+ actionsFromZip: () => actionsFromZip,
34
+ parseJsonl: () => parseJsonl
35
+ });
36
+ module.exports = __toCommonJS(skyRampImport_exports);
37
+ var import_fs = __toESM(require("fs"));
38
+ var import_utils = require("playwright-core/lib/utils");
39
+ const SKYRAMP_ACTIVITIES_FILE = "skyramp_playwright.txt";
40
+ const ACTION_NAMES = /* @__PURE__ */ new Set([
41
+ "marker",
42
+ "comment",
43
+ "beginBlock",
44
+ "endBlock",
45
+ "check",
46
+ "click",
47
+ "hover",
48
+ "closePage",
49
+ "fill",
50
+ "pressSequentially",
51
+ "navigate",
52
+ "openPage",
53
+ "press",
54
+ "select",
55
+ "uncheck",
56
+ "setInputFiles",
57
+ "assertText",
58
+ "assertValue",
59
+ "assertChecked",
60
+ "assertVisible",
61
+ "assertSnapshot",
62
+ "visualSnapshot",
63
+ "assertTableCell",
64
+ "dragTo",
65
+ "dragAndDrop",
66
+ "diagramNodeAdd",
67
+ "diagramLinkAdd",
68
+ "selectArea",
69
+ "tableSnapshot",
70
+ "domSnapshot",
71
+ "fileChooser",
72
+ "penTool",
73
+ "mouse.wheel",
74
+ "mouse.move",
75
+ "mouse.down",
76
+ "mouse.up",
77
+ "modalOpen",
78
+ "modalClose",
79
+ "iframeLoad",
80
+ "assertApiRequest",
81
+ "waitForSelector",
82
+ "waitForTimeout"
83
+ ]);
84
+ function isActionName(name) {
85
+ return ACTION_NAMES.has(name);
86
+ }
87
+ async function actionsFromZip(zipPath) {
88
+ const zip = new import_utils.ZipFile(zipPath);
89
+ try {
90
+ const entries = await zip.entries();
91
+ const entry = entries.find((e) => e === SKYRAMP_ACTIVITIES_FILE) ?? entries.find((e) => e.endsWith(".jsonl")) ?? entries.find((e) => e.endsWith(".txt"));
92
+ if (!entry)
93
+ throw new Error(`No activities file found in ${zipPath}. Expected '${SKYRAMP_ACTIVITIES_FILE}' or a .jsonl/.txt file.`);
94
+ const buffer = await zip.read(entry);
95
+ return parseJsonl(buffer.toString("utf-8"));
96
+ } finally {
97
+ zip.close();
98
+ }
99
+ }
100
+ function actionsFromFile(jsonlPath) {
101
+ return parseJsonl(import_fs.default.readFileSync(jsonlPath, "utf-8"));
102
+ }
103
+ async function actionsFromPath(tracePath) {
104
+ return tracePath.endsWith(".zip") ? await actionsFromZip(tracePath) : actionsFromFile(tracePath);
105
+ }
106
+ function parseJsonl(content) {
107
+ const result = [];
108
+ for (const line of content.split("\n")) {
109
+ const trimmed = line.trim();
110
+ if (!trimmed)
111
+ continue;
112
+ const action = parseLine(trimmed);
113
+ if (action)
114
+ result.push(action);
115
+ }
116
+ return result;
117
+ }
118
+ function parseLine(line) {
119
+ let entry;
120
+ try {
121
+ entry = JSON.parse(line);
122
+ } catch {
123
+ return null;
124
+ }
125
+ if (!entry.name || !isActionName(entry.name))
126
+ return null;
127
+ const { pageGuid, pageAlias, framePath, locator: _locator, ...actionFields } = entry;
128
+ const frame = {
129
+ pageGuid: pageGuid ?? "",
130
+ pageAlias: pageAlias ?? "page",
131
+ framePath: framePath ?? []
132
+ };
133
+ const ts = typeof entry.timestamp === "number" ? entry.timestamp : typeof entry.timestamp === "string" && /^\d+$/.test(entry.timestamp.trim()) ? Number(entry.timestamp.trim()) : Date.now();
134
+ return {
135
+ frame,
136
+ action: actionFields,
137
+ startTime: ts
138
+ };
139
+ }
140
+ // Annotate the CommonJS export names for ESM import in node:
141
+ 0 && (module.exports = {
142
+ actionsFromFile,
143
+ actionsFromPath,
144
+ actionsFromZip,
145
+ parseJsonl
146
+ });