@cmmd-center/forge 0.13.29 → 0.13.31
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/{BunHttpServer-C0oPP_3A.cjs → BunHttpServer-CXndtc1j.cjs} +2 -2
- package/dist/{BunHttpServer-FbbQmsl_.mjs → BunHttpServer-DjilmGOM.mjs} +2 -2
- package/dist/{BunPTY-uyreNRGp.cjs → BunPTY-BiTlUj63.cjs} +1 -1
- package/dist/{BunPTY-DkAIzLIx.mjs → BunPTY-Csgwhbi5.mjs} +1 -1
- package/dist/{BunServices-DC7nhA3w.mjs → BunServices-BZKzHdrG.mjs} +1 -1
- package/dist/{BunServices-DkenwD7S.cjs → BunServices-DsWG7VM1.cjs} +1 -1
- package/dist/{NodeHttpServer-Cjd3bFrD.cjs → NodeHttpServer-B4dCKqYY.cjs} +1 -1
- package/dist/{NodeHttpServer-BJ4l15f-.mjs → NodeHttpServer-Ds3Gp1Gp.mjs} +1 -1
- package/dist/{NodePTY-BehazUMi.cjs → NodePTY-BJ7874MO.cjs} +1 -1
- package/dist/{NodePTY-BhezYy9H.mjs → NodePTY-DgXWLtWp.mjs} +1 -1
- package/dist/{NodeSqliteClient-CfsdC3AB.cjs → NodeSqliteClient-CPsJxxdD.cjs} +1 -1
- package/dist/{NodeSqliteClient-md8xd9hY.mjs → NodeSqliteClient-D29w60zZ.mjs} +1 -1
- package/dist/{SqliteClient-BKB695RF.mjs → SqliteClient-Bgo_s5sA.mjs} +1 -1
- package/dist/{SqliteClient-O1ABIngw.cjs → SqliteClient-k0pbfeIC.cjs} +1 -1
- package/dist/bin.cjs +1879 -2378
- package/dist/bin.mjs +1876 -2375
- package/dist/client/assets/{DiffPanel-CsYeFcEd.js → DiffPanel-rxdARnAn.js} +2 -2
- package/dist/client/assets/{DiffPanel.logic-BhrQueD8.js → DiffPanel.logic-pioWZtAT.js} +2 -2
- package/dist/client/assets/{DiffPanelShell-CssAtWUC.js → DiffPanelShell-CJre8MyV.js} +3 -3
- package/dist/client/assets/{DiffWorkerPoolProvider-C0iUCn9m.js → DiffWorkerPoolProvider-BoinSMK1.js} +2 -2
- package/dist/client/assets/{PullRequestCodePanel-O-XZJVnK.js → PullRequestCodePanel-BR0xA-je.js} +2 -2
- package/dist/client/assets/{Virtualizer-Z2t67-w7.js → Virtualizer-H0mi-vRc.js} +2 -2
- package/dist/client/assets/{index-AMVPSS6N.js → index-DQtjHxYt.js} +6 -6
- package/dist/client/index.html +4 -4
- package/dist/{execAsync-BUcaFQ1D.cjs → execAsync--H9ZZOiC.cjs} +1 -1
- package/dist/{execAsync-BNNdR88o.mjs → execAsync-BJ4g1UuR.mjs} +1 -1
- package/dist/forge-build.json +1 -1
- package/dist/{getMachineId-bsd-3FzKrfVS.cjs → getMachineId-bsd-CJJWgsvW.cjs} +2 -2
- package/dist/{getMachineId-bsd-BuYwT36r.mjs → getMachineId-bsd-CvzjzhCJ.mjs} +2 -2
- package/dist/{getMachineId-darwin-RZKhGQ6C.mjs → getMachineId-darwin-BkjZ6NK7.mjs} +2 -2
- package/dist/{getMachineId-darwin-J2wNbebX.cjs → getMachineId-darwin-hZeIAq-t.cjs} +2 -2
- package/dist/{getMachineId-linux-BDLTrARB.cjs → getMachineId-linux-B4Pn5gp9.cjs} +1 -1
- package/dist/{getMachineId-linux-D5HSP0rH.mjs → getMachineId-linux-BaBxzaf3.mjs} +1 -1
- package/dist/{getMachineId-unsupported-DRh5MFwr.cjs → getMachineId-unsupported-B3jtoOL0.cjs} +1 -1
- package/dist/{getMachineId-unsupported-IaplPZnC.mjs → getMachineId-unsupported-EhCzrOph.mjs} +1 -1
- package/dist/{getMachineId-win-D220ursp.mjs → getMachineId-win-BFwtIsaZ.mjs} +2 -2
- package/dist/{getMachineId-win-BA8dHcjg.cjs → getMachineId-win-Bb4lJE8e.cjs} +2 -2
- package/dist/{open-D8mGyWmt.mjs → open-2-reBrpv.mjs} +1 -1
- package/dist/{open-BAsPVCWX.cjs → open-CghsF25U.cjs} +1 -1
- package/dist/playwright-backend-BONxTCSA.cjs +643 -0
- package/dist/playwright-backend-DVQOhqRO.mjs +642 -0
- package/dist/settle-B6Rn65UV.cjs +28 -0
- package/dist/settle-BJcmpbvq.mjs +23 -0
- package/package.json +1 -1
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { t as settleValueWithin } from "./settle-BJcmpbvq.mjs";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { chromium } from "playwright";
|
|
6
|
+
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/backends/playwright-locators.js
|
|
7
|
+
function locatorForAction(page, action) {
|
|
8
|
+
return action.query ? locatorFromQuery(page, action.query) : page.locator(action.selector ?? "");
|
|
9
|
+
}
|
|
10
|
+
function locatorFromQuery(page, query) {
|
|
11
|
+
switch (query.kind) {
|
|
12
|
+
case "and": return locatorFromQuery(page, query.left).and(locatorFromQuery(page, query.right));
|
|
13
|
+
case "css": return page.locator(query.selector);
|
|
14
|
+
case "filter": return locatorFromQuery(page, query.base).filter(filterOptions(page, query.options));
|
|
15
|
+
case "first": return locatorFromQuery(page, query.base).first();
|
|
16
|
+
case "frame": return locatorInFrame(page, page.frameLocator(query.selector), query.child);
|
|
17
|
+
case "label": return page.getByLabel(query.text, query.options);
|
|
18
|
+
case "last": return locatorFromQuery(page, query.base).last();
|
|
19
|
+
case "locator": return locatorFromQuery(page, query.base).locator(query.selector, filterOptions(page, query.options));
|
|
20
|
+
case "nth": return locatorFromQuery(page, query.base).nth(query.index);
|
|
21
|
+
case "or": return locatorFromQuery(page, query.left).or(locatorFromQuery(page, query.right));
|
|
22
|
+
case "placeholder": return page.getByPlaceholder(query.text, query.options);
|
|
23
|
+
case "role": return page.getByRole(query.role, query.options);
|
|
24
|
+
case "testId": return page.getByTestId(query.testId);
|
|
25
|
+
case "text": return page.getByText(query.text, query.options);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function locatorInFrame(page, frame, query) {
|
|
29
|
+
switch (query.kind) {
|
|
30
|
+
case "css": return frame.locator(query.selector);
|
|
31
|
+
case "filter": return locatorInFrame(page, frame, query.base).filter(filterOptions(page, query.options));
|
|
32
|
+
case "first": return locatorInFrame(page, frame, query.base).first();
|
|
33
|
+
case "label": return frame.getByLabel(query.text, query.options);
|
|
34
|
+
case "last": return locatorInFrame(page, frame, query.base).last();
|
|
35
|
+
case "locator": return locatorInFrame(page, frame, query.base).locator(query.selector, filterOptions(page, query.options));
|
|
36
|
+
case "nth": return locatorInFrame(page, frame, query.base).nth(query.index);
|
|
37
|
+
case "placeholder": return frame.getByPlaceholder(query.text, query.options);
|
|
38
|
+
case "role": return frame.getByRole(query.role, query.options);
|
|
39
|
+
case "testId": return frame.getByTestId(query.testId);
|
|
40
|
+
case "text": return frame.getByText(query.text, query.options);
|
|
41
|
+
case "and":
|
|
42
|
+
case "frame":
|
|
43
|
+
case "or": throw new Error(`Unsupported frame locator query kind: ${query.kind}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function filterOptions(page, options) {
|
|
47
|
+
if (!options) return void 0;
|
|
48
|
+
return {
|
|
49
|
+
...options.has === void 0 ? {} : { has: locatorFromQuery(page, options.has) },
|
|
50
|
+
...options.hasNot === void 0 ? {} : { hasNot: locatorFromQuery(page, options.hasNot) },
|
|
51
|
+
...options.hasNotText === void 0 ? {} : { hasNotText: options.hasNotText },
|
|
52
|
+
...options.hasText === void 0 ? {} : { hasText: options.hasText }
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/backends/playwright-backend.js
|
|
57
|
+
const TAB_METADATA_TIMEOUT_MS = 250;
|
|
58
|
+
const TAB_CONTROL_TIMEOUT_MS = 500;
|
|
59
|
+
var PlaywrightBackend = class {
|
|
60
|
+
options;
|
|
61
|
+
browser;
|
|
62
|
+
context;
|
|
63
|
+
pageIds = /* @__PURE__ */ new WeakMap();
|
|
64
|
+
logs = /* @__PURE__ */ new WeakMap();
|
|
65
|
+
registeredPages = /* @__PURE__ */ new WeakSet();
|
|
66
|
+
constructor(options = {}) {
|
|
67
|
+
this.options = options;
|
|
68
|
+
}
|
|
69
|
+
info() {
|
|
70
|
+
return {
|
|
71
|
+
id: "playwright",
|
|
72
|
+
kind: "playwright",
|
|
73
|
+
name: this.options.name ?? "Playwright Chromium"
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async close() {
|
|
77
|
+
/* v8 ignore next -- defensive cleanup for already-closed Playwright contexts. */
|
|
78
|
+
await this.context?.close().catch(() => void 0);
|
|
79
|
+
await this.browser?.close();
|
|
80
|
+
this.browser = void 0;
|
|
81
|
+
this.context = void 0;
|
|
82
|
+
}
|
|
83
|
+
async listTabs() {
|
|
84
|
+
const context = await this.getContext();
|
|
85
|
+
return Promise.all(context.pages().map((page) => this.toTab(page).info()));
|
|
86
|
+
}
|
|
87
|
+
async selectedTab() {
|
|
88
|
+
const page = (await this.getContext()).pages().at(-1);
|
|
89
|
+
if (page) await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
90
|
+
return page ? this.toTab(page) : void 0;
|
|
91
|
+
}
|
|
92
|
+
async newTab() {
|
|
93
|
+
const page = await (await this.getContext()).newPage();
|
|
94
|
+
await this.preparePage(page);
|
|
95
|
+
await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
96
|
+
return this.toTab(page);
|
|
97
|
+
}
|
|
98
|
+
async getTab(id) {
|
|
99
|
+
const page = (await this.getContext()).pages().find((candidate) => this.idFor(candidate) === id);
|
|
100
|
+
if (!page) throw new Error(`Tab not found: ${id}`);
|
|
101
|
+
await settleValueWithin(page.bringToFront(), TAB_CONTROL_TIMEOUT_MS);
|
|
102
|
+
return this.toTab(page);
|
|
103
|
+
}
|
|
104
|
+
async getContext() {
|
|
105
|
+
/* v8 ignore next -- persistent headed/default launch combinations are covered by smoke, not unit coverage. */
|
|
106
|
+
if (this.options.userDataDir && !this.context) {
|
|
107
|
+
this.context = await chromium.launchPersistentContext(this.options.userDataDir, {
|
|
108
|
+
...this.options.launchOptions,
|
|
109
|
+
...this.options.contextOptions,
|
|
110
|
+
headless: this.options.headless ?? false
|
|
111
|
+
});
|
|
112
|
+
this.browser = this.context.browser() ?? void 0;
|
|
113
|
+
return this.context;
|
|
114
|
+
}
|
|
115
|
+
/* v8 ignore next -- requires a live externally managed Chrome CDP endpoint */
|
|
116
|
+
if (!this.browser && this.options.cdpEndpoint) {
|
|
117
|
+
/* v8 ignore start -- requires a live externally managed Chrome CDP endpoint */
|
|
118
|
+
this.browser = await chromium.connectOverCDP(this.options.cdpEndpoint);
|
|
119
|
+
this.context = this.browser.contexts()[0] ?? await this.browser.newContext(this.options.contextOptions);
|
|
120
|
+
return this.context;
|
|
121
|
+
}
|
|
122
|
+
/* v8 ignore next -- headed/default launch is covered by browser parity smoke. */
|
|
123
|
+
if (!this.browser) this.browser = await chromium.launch({
|
|
124
|
+
...this.options.launchOptions,
|
|
125
|
+
headless: this.options.headless ?? false
|
|
126
|
+
});
|
|
127
|
+
if (!this.context) this.context = await this.browser.newContext(this.options.contextOptions);
|
|
128
|
+
return this.context;
|
|
129
|
+
}
|
|
130
|
+
toTab(page) {
|
|
131
|
+
this.registerPage(page);
|
|
132
|
+
return new PlaywrightTabHandle(page, this.idFor(page), this.logsFor(page));
|
|
133
|
+
}
|
|
134
|
+
async preparePage(page) {
|
|
135
|
+
this.registerPage(page);
|
|
136
|
+
const bounds = this.options.windowBounds;
|
|
137
|
+
if (!bounds) return;
|
|
138
|
+
await settleValueWithin(page.setViewportSize({
|
|
139
|
+
width: bounds.width,
|
|
140
|
+
height: bounds.height
|
|
141
|
+
}), TAB_CONTROL_TIMEOUT_MS);
|
|
142
|
+
const sessionResult = await settleValueWithin(page.context().newCDPSession(page), TAB_CONTROL_TIMEOUT_MS);
|
|
143
|
+
/* v8 ignore next -- Playwright CDP attachment failures are bounded and covered by the shared timeout primitive. */
|
|
144
|
+
if (sessionResult.status !== "fulfilled") return;
|
|
145
|
+
const session = sessionResult.value;
|
|
146
|
+
try {
|
|
147
|
+
const windowResult = await settleValueWithin(session.send("Browser.getWindowForTarget"), TAB_CONTROL_TIMEOUT_MS);
|
|
148
|
+
/* v8 ignore next -- Chromium may decline window control in unsupported headless/CDP environments. */
|
|
149
|
+
if (windowResult.status !== "fulfilled" || typeof windowResult.value.windowId !== "number") return;
|
|
150
|
+
await settleValueWithin(session.send("Browser.setWindowBounds", {
|
|
151
|
+
bounds: {
|
|
152
|
+
height: bounds.height,
|
|
153
|
+
left: bounds.left ?? 0,
|
|
154
|
+
top: bounds.top ?? 0,
|
|
155
|
+
width: bounds.width,
|
|
156
|
+
windowState: "normal"
|
|
157
|
+
},
|
|
158
|
+
windowId: windowResult.value.windowId
|
|
159
|
+
}), TAB_CONTROL_TIMEOUT_MS);
|
|
160
|
+
} finally {
|
|
161
|
+
await settleValueWithin(session.detach(), TAB_CONTROL_TIMEOUT_MS);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
registerPage(page) {
|
|
165
|
+
this.idFor(page);
|
|
166
|
+
this.logsFor(page);
|
|
167
|
+
if (this.registeredPages.has(page)) return;
|
|
168
|
+
this.registeredPages.add(page);
|
|
169
|
+
page.on("console", (message) => {
|
|
170
|
+
this.logsFor(page).push(toConsoleLog(message, page.url()));
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
idFor(page) {
|
|
174
|
+
let id = this.pageIds.get(page);
|
|
175
|
+
if (!id) {
|
|
176
|
+
id = `tab_${randomUUID()}`;
|
|
177
|
+
this.pageIds.set(page, id);
|
|
178
|
+
}
|
|
179
|
+
return id;
|
|
180
|
+
}
|
|
181
|
+
logsFor(page) {
|
|
182
|
+
let entries = this.logs.get(page);
|
|
183
|
+
if (!entries) {
|
|
184
|
+
entries = [];
|
|
185
|
+
this.logs.set(page, entries);
|
|
186
|
+
}
|
|
187
|
+
return entries;
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
var PlaywrightTabHandle = class {
|
|
191
|
+
page;
|
|
192
|
+
id;
|
|
193
|
+
logEntries;
|
|
194
|
+
constructor(page, id, logEntries) {
|
|
195
|
+
this.page = page;
|
|
196
|
+
this.id = id;
|
|
197
|
+
this.logEntries = logEntries;
|
|
198
|
+
}
|
|
199
|
+
async info() {
|
|
200
|
+
const [title, history] = await Promise.all([settleValueWithin(this.page.title(), TAB_METADATA_TIMEOUT_MS), settleValueWithin(this.historyState(), TAB_METADATA_TIMEOUT_MS)]);
|
|
201
|
+
const base = title.status !== "fulfilled" ? {
|
|
202
|
+
id: this.id,
|
|
203
|
+
url: this.page.url()
|
|
204
|
+
} : {
|
|
205
|
+
id: this.id,
|
|
206
|
+
title: title.value,
|
|
207
|
+
url: this.page.url()
|
|
208
|
+
};
|
|
209
|
+
/* v8 ignore next -- metadata timeout fallback is covered through AgentBrowser's bounded observation contract. */
|
|
210
|
+
return history.status === "fulfilled" ? {
|
|
211
|
+
...base,
|
|
212
|
+
...history.value
|
|
213
|
+
} : base;
|
|
214
|
+
}
|
|
215
|
+
async historyState() {
|
|
216
|
+
const sessionResult = await settleValueWithin(this.page.context().newCDPSession(this.page), TAB_METADATA_TIMEOUT_MS);
|
|
217
|
+
/* v8 ignore next -- Playwright CDP attachment failures are bounded and covered by the shared timeout primitive. */
|
|
218
|
+
if (sessionResult.status !== "fulfilled") return {};
|
|
219
|
+
const session = sessionResult.value;
|
|
220
|
+
try {
|
|
221
|
+
const historyResult = await settleValueWithin(session.send("Page.getNavigationHistory"), TAB_METADATA_TIMEOUT_MS);
|
|
222
|
+
/* v8 ignore next -- Chromium navigation-history failures are bounded external CDP behavior. */
|
|
223
|
+
if (historyResult.status !== "fulfilled") return {};
|
|
224
|
+
const history = historyResult.value;
|
|
225
|
+
return {
|
|
226
|
+
canGoBack: history.currentIndex > 0,
|
|
227
|
+
canGoForward: history.currentIndex < history.entries.length - 1
|
|
228
|
+
};
|
|
229
|
+
} finally {
|
|
230
|
+
await settleValueWithin(session.detach(), TAB_METADATA_TIMEOUT_MS);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
async goto(url) {
|
|
234
|
+
await this.page.goto(url, { waitUntil: "domcontentloaded" });
|
|
235
|
+
}
|
|
236
|
+
async reload() {
|
|
237
|
+
await this.page.reload({ waitUntil: "domcontentloaded" });
|
|
238
|
+
}
|
|
239
|
+
async forceReload() {
|
|
240
|
+
const client = await this.page.context().newCDPSession(this.page);
|
|
241
|
+
try {
|
|
242
|
+
await client.send("Page.reload", { ignoreCache: true });
|
|
243
|
+
/* v8 ignore next -- defensive fallback for navigations that do not settle after CDP reload. */
|
|
244
|
+
await this.page.waitForLoadState("domcontentloaded", { timeout: 3e4 }).catch(() => void 0);
|
|
245
|
+
} finally {
|
|
246
|
+
await client.detach();
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async back() {
|
|
250
|
+
await this.page.goBack({ waitUntil: "domcontentloaded" });
|
|
251
|
+
}
|
|
252
|
+
async forward() {
|
|
253
|
+
await this.page.goForward({ waitUntil: "domcontentloaded" });
|
|
254
|
+
}
|
|
255
|
+
async close() {
|
|
256
|
+
await this.page.close();
|
|
257
|
+
}
|
|
258
|
+
async screenshot(options = {}) {
|
|
259
|
+
const bytes = await this.page.screenshot({
|
|
260
|
+
...options.fullPage === void 0 ? {} : { fullPage: options.fullPage },
|
|
261
|
+
...options.clip === void 0 ? {} : { clip: options.clip },
|
|
262
|
+
...options.mimeType === void 0 ? {} : { type: options.mimeType === "image/jpeg" ? "jpeg" : "png" },
|
|
263
|
+
...options.quality === void 0 ? {} : { quality: options.quality }
|
|
264
|
+
});
|
|
265
|
+
if (options.maxBytes !== void 0 && bytes.byteLength > options.maxBytes) throw new Error(`Browser screenshot exceeded maxBytes=${options.maxBytes}. size=${bytes.byteLength}`);
|
|
266
|
+
return bytes;
|
|
267
|
+
}
|
|
268
|
+
async setViewport(size) {
|
|
269
|
+
await this.page.setViewportSize({
|
|
270
|
+
width: Math.round(size.width),
|
|
271
|
+
height: Math.round(size.height)
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
async setZoom(zoom) {
|
|
275
|
+
/* v8 ignore next 3 -- browser-executed callback runs outside Node coverage */
|
|
276
|
+
await this.page.evaluate((level) => {
|
|
277
|
+
document.documentElement.style.zoom = String(level);
|
|
278
|
+
}, zoom.level);
|
|
279
|
+
}
|
|
280
|
+
async clearCookies() {
|
|
281
|
+
await this.page.context().clearCookies();
|
|
282
|
+
}
|
|
283
|
+
async clearCache() {
|
|
284
|
+
const client = await this.page.context().newCDPSession(this.page);
|
|
285
|
+
try {
|
|
286
|
+
await client.send("Network.clearBrowserCache");
|
|
287
|
+
} finally {
|
|
288
|
+
await client.detach();
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
async domSnapshot() {
|
|
292
|
+
return this.page.locator("body").ariaSnapshot({ timeout: 5e3 });
|
|
293
|
+
}
|
|
294
|
+
async evaluate(expression, arg) {
|
|
295
|
+
/* v8 ignore next 4 -- browser-executed callback runs outside Node coverage */
|
|
296
|
+
return this.page.evaluate((input) => {
|
|
297
|
+
return new Function("arg", `return (${input.expression})(arg);`)(input.arg);
|
|
298
|
+
}, {
|
|
299
|
+
arg,
|
|
300
|
+
expression
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async waitForLoadState(state = "load", timeoutMs) {
|
|
304
|
+
await this.page.waitForLoadState(state, timeoutOptions(timeoutMs));
|
|
305
|
+
}
|
|
306
|
+
async waitForURL(url, timeoutMs) {
|
|
307
|
+
await this.page.waitForURL(url, timeoutOptions(timeoutMs));
|
|
308
|
+
}
|
|
309
|
+
async waitForDownload(timeoutMs) {
|
|
310
|
+
return toBrowserDownload(await this.page.waitForEvent("download", timeoutOptions(timeoutMs)));
|
|
311
|
+
}
|
|
312
|
+
async elementInfo(options) {
|
|
313
|
+
/* v8 ignore start -- browser-executed DOM inspection runs outside Node coverage */
|
|
314
|
+
return this.page.evaluate(({ x, y, includeNonInteractable }) => {
|
|
315
|
+
const element = document.elementFromPoint(x, y);
|
|
316
|
+
if (!element || element === document.documentElement || element === document.body) return;
|
|
317
|
+
const rect = element.getBoundingClientRect();
|
|
318
|
+
if (rect.width <= 0 || rect.height <= 0) return;
|
|
319
|
+
const style = window.getComputedStyle(element);
|
|
320
|
+
if (!includeNonInteractable && (style.visibility === "hidden" || style.display === "none" || style.pointerEvents === "none")) return;
|
|
321
|
+
const tagName = element.tagName.toLowerCase();
|
|
322
|
+
const visibleText = visibleElementText(element);
|
|
323
|
+
const ariaName = element.getAttribute("aria-label") ?? element.getAttribute("alt") ?? void 0;
|
|
324
|
+
const role = element.getAttribute("role") ?? inferRole(element);
|
|
325
|
+
const candidates = selectorCandidates(element);
|
|
326
|
+
const testId = element.getAttribute("data-testid") ?? element.getAttribute("data-test-id") ?? void 0;
|
|
327
|
+
const nodeId = ensureNodeId(element);
|
|
328
|
+
const preview = compactText(`${tagName}${role ? ` role=${role}` : ""}${ariaName ? ` aria="${ariaName}"` : ""}${visibleText ? ` text="${visibleText}"` : ""}`);
|
|
329
|
+
return {
|
|
330
|
+
...ariaName ? { ariaName } : {},
|
|
331
|
+
boundingBox: {
|
|
332
|
+
x: rect.x,
|
|
333
|
+
y: rect.y,
|
|
334
|
+
width: rect.width,
|
|
335
|
+
height: rect.height
|
|
336
|
+
},
|
|
337
|
+
nodeId,
|
|
338
|
+
preview,
|
|
339
|
+
...role ? { role } : {},
|
|
340
|
+
selector: {
|
|
341
|
+
candidates,
|
|
342
|
+
primary: candidates[0] ?? null
|
|
343
|
+
},
|
|
344
|
+
tagName,
|
|
345
|
+
...testId ? { testId } : {},
|
|
346
|
+
...visibleText ? { visibleText } : {}
|
|
347
|
+
};
|
|
348
|
+
function compactText(value) {
|
|
349
|
+
return value.replace(/\s+/g, " ").trim().slice(0, 180);
|
|
350
|
+
}
|
|
351
|
+
function visibleElementText(node) {
|
|
352
|
+
if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement) return compactText(node.value || node.placeholder || "");
|
|
353
|
+
if (node instanceof HTMLSelectElement) return compactText(node.selectedOptions[0]?.textContent ?? node.value);
|
|
354
|
+
return compactText(node.textContent ?? "") || void 0;
|
|
355
|
+
}
|
|
356
|
+
function inferRole(node) {
|
|
357
|
+
if (node instanceof HTMLAnchorElement && node.href) return "link";
|
|
358
|
+
if (node instanceof HTMLButtonElement) return "button";
|
|
359
|
+
if (node instanceof HTMLInputElement) return node.type || "textbox";
|
|
360
|
+
if (node instanceof HTMLSelectElement) return "combobox";
|
|
361
|
+
if (node instanceof HTMLTextAreaElement) return "textbox";
|
|
362
|
+
if (/^h[1-6]$/i.test(node.tagName)) return "heading";
|
|
363
|
+
}
|
|
364
|
+
function ensureNodeId(node) {
|
|
365
|
+
const existing = node.getAttribute("data-agent-browser-node-id");
|
|
366
|
+
if (existing) return Number(existing);
|
|
367
|
+
const next = Number(document.documentElement.getAttribute("data-agent-browser-next-node-id") ?? "1");
|
|
368
|
+
document.documentElement.setAttribute("data-agent-browser-next-node-id", String(next + 1));
|
|
369
|
+
node.setAttribute("data-agent-browser-node-id", String(next));
|
|
370
|
+
return next;
|
|
371
|
+
}
|
|
372
|
+
function selectorCandidates(node) {
|
|
373
|
+
const candidates = [];
|
|
374
|
+
if (node.id) candidates.push(`#${cssEscape(node.id)}`);
|
|
375
|
+
const testId = node.getAttribute("data-testid") ?? node.getAttribute("data-test-id");
|
|
376
|
+
if (testId) candidates.push(`[data-testid="${cssString(testId)}"]`);
|
|
377
|
+
const href = node.getAttribute("href");
|
|
378
|
+
if (href) candidates.push(`${node.tagName.toLowerCase()}[href="${cssString(href)}"]`);
|
|
379
|
+
const aria = node.getAttribute("aria-label");
|
|
380
|
+
if (aria) candidates.push(`${node.tagName.toLowerCase()}[aria-label="${cssString(aria)}"]`);
|
|
381
|
+
const name = node.getAttribute("name");
|
|
382
|
+
if (name) candidates.push(`${node.tagName.toLowerCase()}[name="${cssString(name)}"]`);
|
|
383
|
+
const parts = [];
|
|
384
|
+
let current = node;
|
|
385
|
+
while (current && current !== document.body && current !== document.documentElement && parts.length < 5) {
|
|
386
|
+
let part = current.tagName.toLowerCase();
|
|
387
|
+
const name = current.getAttribute("name");
|
|
388
|
+
if (name) part += `[name="${cssString(name)}"]`;
|
|
389
|
+
else {
|
|
390
|
+
const className = Array.from(current.classList).find(Boolean);
|
|
391
|
+
if (className) part += `.${cssEscape(className)}`;
|
|
392
|
+
}
|
|
393
|
+
const parent = current.parentElement;
|
|
394
|
+
if (parent) {
|
|
395
|
+
const siblings = Array.from(parent.children).filter((sibling) => sibling.tagName === current?.tagName);
|
|
396
|
+
if (siblings.length > 1) part += `:nth-of-type(${siblings.indexOf(current) + 1})`;
|
|
397
|
+
}
|
|
398
|
+
parts.unshift(part);
|
|
399
|
+
const candidate = parts.join(" > ");
|
|
400
|
+
if (document.querySelectorAll(candidate).length === 1) {
|
|
401
|
+
candidates.push(candidate);
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
current = parent;
|
|
405
|
+
}
|
|
406
|
+
const fallback = parts.join(" > ") || node.tagName.toLowerCase();
|
|
407
|
+
candidates.push(fallback);
|
|
408
|
+
return Array.from(new Set(candidates));
|
|
409
|
+
}
|
|
410
|
+
function cssEscape(value) {
|
|
411
|
+
return CSS.escape(value);
|
|
412
|
+
}
|
|
413
|
+
function cssString(value) {
|
|
414
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
415
|
+
}
|
|
416
|
+
}, options);
|
|
417
|
+
/* v8 ignore stop */
|
|
418
|
+
}
|
|
419
|
+
async elementScreenshot(options) {
|
|
420
|
+
const element = await this.elementInfo(options);
|
|
421
|
+
if (!element?.boundingBox) return void 0;
|
|
422
|
+
return this.screenshot({ clip: element.boundingBox });
|
|
423
|
+
}
|
|
424
|
+
async click(action) {
|
|
425
|
+
const locator = this.locatorFor(action);
|
|
426
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
427
|
+
await locator.click(timeoutOptions(action.timeoutMs));
|
|
428
|
+
}
|
|
429
|
+
async doubleClick(action) {
|
|
430
|
+
const locator = this.locatorFor(action);
|
|
431
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
432
|
+
await locator.dblclick(timeoutOptions(action.timeoutMs));
|
|
433
|
+
}
|
|
434
|
+
async fill(action, value) {
|
|
435
|
+
const locator = this.locatorFor(action);
|
|
436
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
437
|
+
await locator.fill(value, timeoutOptions(action.timeoutMs));
|
|
438
|
+
}
|
|
439
|
+
async type(action, value) {
|
|
440
|
+
const locator = this.locatorFor(action);
|
|
441
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
442
|
+
await locator.pressSequentially(value, timeoutOptions(action.timeoutMs));
|
|
443
|
+
}
|
|
444
|
+
async press(action, key) {
|
|
445
|
+
const locator = this.locatorFor(action);
|
|
446
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
447
|
+
await locator.press(key, timeoutOptions(action.timeoutMs));
|
|
448
|
+
}
|
|
449
|
+
async select(action, value) {
|
|
450
|
+
const locator = this.locatorFor(action);
|
|
451
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
452
|
+
await locator.selectOption(value, timeoutOptions(action.timeoutMs));
|
|
453
|
+
}
|
|
454
|
+
async check(action, checked) {
|
|
455
|
+
const locator = this.locatorFor(action);
|
|
456
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
457
|
+
await locator.setChecked(checked, timeoutOptions(action.timeoutMs));
|
|
458
|
+
}
|
|
459
|
+
async text(action) {
|
|
460
|
+
const locator = this.locatorFor(action);
|
|
461
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
462
|
+
return locator.textContent(timeoutOptions(action.timeoutMs));
|
|
463
|
+
}
|
|
464
|
+
async innerText(action) {
|
|
465
|
+
const locator = this.locatorFor(action);
|
|
466
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
467
|
+
return locator.innerText(timeoutOptions(action.timeoutMs));
|
|
468
|
+
}
|
|
469
|
+
async allTextContents(action) {
|
|
470
|
+
return this.locatorFor(action).allTextContents();
|
|
471
|
+
}
|
|
472
|
+
async attribute(action, name) {
|
|
473
|
+
const locator = this.locatorFor(action);
|
|
474
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
475
|
+
return locator.getAttribute(name, timeoutOptions(action.timeoutMs));
|
|
476
|
+
}
|
|
477
|
+
async isVisible(action) {
|
|
478
|
+
const locator = this.locatorFor(action);
|
|
479
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
480
|
+
return locator.isVisible(timeoutOptions(action.timeoutMs));
|
|
481
|
+
}
|
|
482
|
+
async isEnabled(action) {
|
|
483
|
+
const locator = this.locatorFor(action);
|
|
484
|
+
await assertSingle(locator.count(), locatorActionLabel(action));
|
|
485
|
+
return locator.isEnabled(timeoutOptions(action.timeoutMs));
|
|
486
|
+
}
|
|
487
|
+
async locatorCount(action) {
|
|
488
|
+
return this.locatorFor(action).count();
|
|
489
|
+
}
|
|
490
|
+
async waitForLocator(action, state) {
|
|
491
|
+
await this.locatorFor(action).waitFor({
|
|
492
|
+
...state === void 0 ? {} : { state },
|
|
493
|
+
...timeoutOptions(action.timeoutMs)
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
async cuaMove(point) {
|
|
497
|
+
await this.page.mouse.move(point.x, point.y);
|
|
498
|
+
}
|
|
499
|
+
async cuaClick(point) {
|
|
500
|
+
await this.page.mouse.click(point.x, point.y, { button: mouseButton(point.button) });
|
|
501
|
+
}
|
|
502
|
+
async cuaDoubleClick(point) {
|
|
503
|
+
await this.page.mouse.dblclick(point.x, point.y);
|
|
504
|
+
}
|
|
505
|
+
async cuaDrag(path) {
|
|
506
|
+
const [start, ...rest] = path;
|
|
507
|
+
if (!start) return;
|
|
508
|
+
await this.page.mouse.move(start.x, start.y);
|
|
509
|
+
await this.page.mouse.down();
|
|
510
|
+
for (const point of rest) await this.page.mouse.move(point.x, point.y);
|
|
511
|
+
await this.page.mouse.up();
|
|
512
|
+
}
|
|
513
|
+
async cuaScroll(input) {
|
|
514
|
+
await this.page.mouse.move(input.x, input.y);
|
|
515
|
+
await this.page.mouse.wheel(input.scrollX, input.scrollY);
|
|
516
|
+
}
|
|
517
|
+
async cuaType(text) {
|
|
518
|
+
await this.page.keyboard.type(text);
|
|
519
|
+
}
|
|
520
|
+
async cuaKeypress(keys) {
|
|
521
|
+
await this.page.keyboard.press(keys.join("+"));
|
|
522
|
+
}
|
|
523
|
+
async visibleDom() {
|
|
524
|
+
return this.page.evaluate(`(() => {
|
|
525
|
+
let nextId = Number(document.documentElement.getAttribute("data-agent-browser-next-node-id") || "1");
|
|
526
|
+
function walk(element) {
|
|
527
|
+
const rect = element.getBoundingClientRect();
|
|
528
|
+
const style = window.getComputedStyle(element);
|
|
529
|
+
if (rect.width <= 0 || rect.height <= 0 || style.display === "none" || style.visibility === "hidden") {
|
|
530
|
+
return undefined;
|
|
531
|
+
}
|
|
532
|
+
let nodeId = element.getAttribute("data-agent-browser-node-id");
|
|
533
|
+
if (!nodeId) {
|
|
534
|
+
nodeId = String(nextId++);
|
|
535
|
+
element.setAttribute("data-agent-browser-node-id", nodeId);
|
|
536
|
+
}
|
|
537
|
+
const tagName = element.tagName.toLowerCase();
|
|
538
|
+
const visibleText = (element.textContent ?? "").replace(/\s+/g, " ").trim().slice(0, 120) || undefined;
|
|
539
|
+
const role = element.getAttribute("role") ?? undefined;
|
|
540
|
+
const ariaName = element.getAttribute("aria-label") ?? undefined;
|
|
541
|
+
const children = Array.from(element.children).map(walk).filter(Boolean);
|
|
542
|
+
return {
|
|
543
|
+
...(ariaName ? { ariaName } : {}),
|
|
544
|
+
boundingBox: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
545
|
+
...(children.length ? { children } : {}),
|
|
546
|
+
nodeId,
|
|
547
|
+
preview: (tagName + (ariaName ? ' "' + ariaName + '"' : "") + (visibleText ? " " + visibleText : "")).slice(0, 180),
|
|
548
|
+
...(role ? { role } : {}),
|
|
549
|
+
tagName,
|
|
550
|
+
...(visibleText ? { visibleText } : {})
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
document.documentElement.setAttribute("data-agent-browser-next-node-id", String(nextId));
|
|
554
|
+
return walk(document.body) ?? { nodeId: "body", preview: "body", tagName: "body" };
|
|
555
|
+
})()`);
|
|
556
|
+
}
|
|
557
|
+
async domClick(nodeId) {
|
|
558
|
+
await this.byNodeId(nodeId).click();
|
|
559
|
+
}
|
|
560
|
+
async domDoubleClick(nodeId) {
|
|
561
|
+
await this.byNodeId(nodeId).dblclick();
|
|
562
|
+
}
|
|
563
|
+
async domScroll(input) {
|
|
564
|
+
if (input.nodeId) {
|
|
565
|
+
/* v8 ignore next -- browser-executed DOM callback runs outside Node coverage */
|
|
566
|
+
await this.byNodeId(input.nodeId).evaluate((element, delta) => element.scrollBy(delta.x, delta.y), {
|
|
567
|
+
x: input.x,
|
|
568
|
+
y: input.y
|
|
569
|
+
});
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
await this.page.mouse.wheel(input.x, input.y);
|
|
573
|
+
}
|
|
574
|
+
async domType(text) {
|
|
575
|
+
await this.page.keyboard.type(text);
|
|
576
|
+
}
|
|
577
|
+
async domKeypress(keys) {
|
|
578
|
+
await this.page.keyboard.press(keys.join("+"));
|
|
579
|
+
}
|
|
580
|
+
async clipboardReadText() {
|
|
581
|
+
/* v8 ignore next -- browser-executed callback runs outside Node coverage */
|
|
582
|
+
return this.page.evaluate(() => navigator.clipboard.readText());
|
|
583
|
+
}
|
|
584
|
+
async clipboardWriteText(text) {
|
|
585
|
+
/* v8 ignore next -- browser-executed callback runs outside Node coverage */
|
|
586
|
+
await this.page.evaluate((value) => navigator.clipboard.writeText(value), text);
|
|
587
|
+
}
|
|
588
|
+
async logs(limit = 100) {
|
|
589
|
+
return this.logEntries.slice(-limit);
|
|
590
|
+
}
|
|
591
|
+
byNodeId(nodeId) {
|
|
592
|
+
return this.page.locator(`[data-agent-browser-node-id="${cssStringForSelector(nodeId)}"]`);
|
|
593
|
+
}
|
|
594
|
+
locatorFor(action) {
|
|
595
|
+
return locatorForAction(this.page, action);
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
function locatorActionLabel(action) {
|
|
599
|
+
/* v8 ignore next -- valid public calls always supply selector or query; malformed calls are rejected downstream. */
|
|
600
|
+
return action.selector ?? action.query?.kind ?? "locator";
|
|
601
|
+
}
|
|
602
|
+
function mouseButton(button) {
|
|
603
|
+
if (button === 2) return "middle";
|
|
604
|
+
if (button === 3) return "right";
|
|
605
|
+
return "left";
|
|
606
|
+
}
|
|
607
|
+
function cssStringForSelector(value) {
|
|
608
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
|
|
609
|
+
}
|
|
610
|
+
function timeoutOptions(timeoutMs) {
|
|
611
|
+
return timeoutMs === void 0 ? {} : { timeout: timeoutMs };
|
|
612
|
+
}
|
|
613
|
+
function toBrowserDownload(download) {
|
|
614
|
+
return {
|
|
615
|
+
failure: () => download.failure(),
|
|
616
|
+
path: () => download.path().catch(() => null),
|
|
617
|
+
saveAs: (path) => download.saveAs(path),
|
|
618
|
+
suggestedFilename: () => download.suggestedFilename(),
|
|
619
|
+
url: () => download.url()
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
async function assertSingle(countPromise, selector) {
|
|
623
|
+
const count = await countPromise;
|
|
624
|
+
if (count !== 1) throw new Error(`Selector must resolve to exactly one element. selector=${selector} count=${count}`);
|
|
625
|
+
}
|
|
626
|
+
function toConsoleLog(message, url) {
|
|
627
|
+
return {
|
|
628
|
+
level: normalizeLevel(message.type()),
|
|
629
|
+
message: message.text(),
|
|
630
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
631
|
+
url
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
function normalizeLevel(level) {
|
|
635
|
+
if (level === "debug" || level === "info" || level === "log" || level === "warn" || level === "error") return level;
|
|
636
|
+
/* v8 ignore next -- Playwright currently normalizes known console message types */
|
|
637
|
+
return "log";
|
|
638
|
+
}
|
|
639
|
+
//#endregion
|
|
640
|
+
export { PlaywrightBackend };
|
|
641
|
+
|
|
642
|
+
//# sourceMappingURL=playwright-backend-DVQOhqRO.mjs.map
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/core/settle.js
|
|
4
|
+
async function settleValueWithin(promise, timeoutMs) {
|
|
5
|
+
let timer;
|
|
6
|
+
try {
|
|
7
|
+
return await Promise.race([promise.then((value) => ({
|
|
8
|
+
status: "fulfilled",
|
|
9
|
+
value
|
|
10
|
+
}), (error) => ({
|
|
11
|
+
error,
|
|
12
|
+
status: "rejected"
|
|
13
|
+
})), new Promise((resolve) => {
|
|
14
|
+
timer = setTimeout(() => resolve({ status: "timed-out" }), timeoutMs);
|
|
15
|
+
})]);
|
|
16
|
+
} finally {
|
|
17
|
+
clearTimeout(timer);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
Object.defineProperty(exports, "settleValueWithin", {
|
|
22
|
+
enumerable: true,
|
|
23
|
+
get: function() {
|
|
24
|
+
return settleValueWithin;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
//# sourceMappingURL=settle-B6Rn65UV.cjs.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
//#region ../../node_modules/.bun/@cmmd-center+agent-browser@0.6.2+69e331b0475d65dc/node_modules/@cmmd-center/agent-browser/dist/core/settle.js
|
|
4
|
+
async function settleValueWithin(promise, timeoutMs) {
|
|
5
|
+
let timer;
|
|
6
|
+
try {
|
|
7
|
+
return await Promise.race([promise.then((value) => ({
|
|
8
|
+
status: "fulfilled",
|
|
9
|
+
value
|
|
10
|
+
}), (error) => ({
|
|
11
|
+
error,
|
|
12
|
+
status: "rejected"
|
|
13
|
+
})), new Promise((resolve) => {
|
|
14
|
+
timer = setTimeout(() => resolve({ status: "timed-out" }), timeoutMs);
|
|
15
|
+
})]);
|
|
16
|
+
} finally {
|
|
17
|
+
clearTimeout(timer);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { settleValueWithin as t };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=settle-BJcmpbvq.mjs.map
|