teamshare-bridge 0.26.11 → 0.26.13
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/bridge/local-server.js +6 -10
- package/dist/bridge/local-server.js.map +1 -1
- package/dist/cli/commands/research.js +15 -0
- package/dist/cli/commands/research.js.map +1 -1
- package/dist/lib/browser/batch.d.ts +47 -2
- package/dist/lib/browser/batch.js +48 -5
- package/dist/lib/browser/batch.js.map +1 -1
- package/dist/lib/browser/browse-cdp.js +5 -1
- package/dist/lib/browser/browse-cdp.js.map +1 -1
- package/dist/lib/browser/browse-editor.js +8 -0
- package/dist/lib/browser/browse-editor.js.map +1 -1
- package/dist/lib/browser/cdp.d.ts +2 -0
- package/dist/lib/browser/cdp.js +8 -0
- package/dist/lib/browser/cdp.js.map +1 -1
- package/dist/lib/browser/index.d.ts +3 -1
- package/dist/lib/browser/index.js +12 -1
- package/dist/lib/browser/index.js.map +1 -1
- package/dist/lib/browser/login.d.ts +67 -25
- package/dist/lib/browser/login.js +681 -174
- package/dist/lib/browser/login.js.map +1 -1
- package/dist/lib/browser/manager.d.ts +26 -0
- package/dist/lib/browser/manager.js +48 -0
- package/dist/lib/browser/manager.js.map +1 -1
- package/dist/lib/browser/network-log.d.ts +9 -0
- package/dist/lib/browser/network-log.js +21 -0
- package/dist/lib/browser/network-log.js.map +1 -1
- package/dist/lib/browser/page-context.d.ts +176 -0
- package/dist/lib/browser/page-context.js +637 -0
- package/dist/lib/browser/page-context.js.map +1 -0
- package/dist/lib/browser/page-events.d.ts +39 -0
- package/dist/lib/browser/page-events.js +128 -0
- package/dist/lib/browser/page-events.js.map +1 -0
- package/dist/lib/browser/screen-change.js +3 -0
- package/dist/lib/browser/screen-change.js.map +1 -1
- package/dist/lib/browser/session-pool.d.ts +44 -0
- package/dist/lib/browser/session-pool.js +128 -0
- package/dist/lib/browser/session-pool.js.map +1 -0
- package/dist/lib/browser/session.d.ts +115 -1
- package/dist/lib/browser/session.js +355 -2
- package/dist/lib/browser/session.js.map +1 -1
- package/dist/lib/config.js +25 -4
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/orchestrator/handlers/browser.js +283 -40
- package/dist/lib/orchestrator/handlers/browser.js.map +1 -1
- package/dist/lib/tools/browser-tool.d.ts +2 -2
- package/dist/lib/tools/browser-tool.js +58 -19
- package/dist/lib/tools/browser-tool.js.map +1 -1
- package/package.json +1 -1
- package/templates/common/AGENTS.md.tpl +19 -19
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_TEXT_CAP = exports.MAX_TOASTS = exports.MAX_ERRORS = exports.MAX_DIALOGS = exports.MAX_FIELDS = exports.WAIT_FOR_VALUES = exports.PAGE_ERROR_SELECTORS = void 0;
|
|
4
|
+
exports.buildPageStateScript = buildPageStateScript;
|
|
5
|
+
exports.readPageState = readPageState;
|
|
6
|
+
exports.compactPageState = compactPageState;
|
|
7
|
+
exports.buildCompactStateScript = buildCompactStateScript;
|
|
8
|
+
exports.readCompactState = readCompactState;
|
|
9
|
+
exports.renderPageStateText = renderPageStateText;
|
|
10
|
+
exports.buildWaitProbeScript = buildWaitProbeScript;
|
|
11
|
+
exports.emptyPageSnapshot = emptyPageSnapshot;
|
|
12
|
+
/**
|
|
13
|
+
* Rich page state for the debug/MCP browser (2026-10).
|
|
14
|
+
*
|
|
15
|
+
* The auto-answer loop already extracts title/URL/headings/errors/toasts/full
|
|
16
|
+
* text (`extractPageContext` in browse-editor.ts). The debug browser had only a
|
|
17
|
+
* flat text read, so a QA agent could not SEE a login dialog, its buttons, its
|
|
18
|
+
* field state, a toast that had already disappeared, or the validation error
|
|
19
|
+
* that explained a failed submit. In the live Soludesks run that cost five
|
|
20
|
+
* minutes of raw `evaluate` calls and still ended on the wrong page.
|
|
21
|
+
*
|
|
22
|
+
* This module is the shared, structured equivalent: one in-page script returns
|
|
23
|
+
* a JSON-safe `PageState` with the topmost dialog, its buttons and fields,
|
|
24
|
+
* visible errors, the persistent toast buffer (page-events.ts), headings,
|
|
25
|
+
* focus, busy state and optional page text. `compactPageState` is the bounded
|
|
26
|
+
* version attached to ordinary action results.
|
|
27
|
+
*
|
|
28
|
+
* Rules:
|
|
29
|
+
* - NEVER return a field VALUE - only `valueLength` (a password must not
|
|
30
|
+
* travel through a tool result).
|
|
31
|
+
* - The topmost open dialog is the interaction scope. Page fields behind a
|
|
32
|
+
* modal are not offered as primary targets.
|
|
33
|
+
* - Everything is capped so one snapshot cannot balloon a tool response.
|
|
34
|
+
*/
|
|
35
|
+
const cdp_1 = require("./cdp");
|
|
36
|
+
const DEFAULT_TEXT_CAP = 12_000;
|
|
37
|
+
exports.DEFAULT_TEXT_CAP = DEFAULT_TEXT_CAP;
|
|
38
|
+
const MAX_FIELDS = 40;
|
|
39
|
+
exports.MAX_FIELDS = MAX_FIELDS;
|
|
40
|
+
const MAX_DIALOGS = 8;
|
|
41
|
+
exports.MAX_DIALOGS = MAX_DIALOGS;
|
|
42
|
+
const MAX_ERRORS = 8;
|
|
43
|
+
exports.MAX_ERRORS = MAX_ERRORS;
|
|
44
|
+
const MAX_TOASTS = 10;
|
|
45
|
+
exports.MAX_TOASTS = MAX_TOASTS;
|
|
46
|
+
/**
|
|
47
|
+
* Selectors that surface user-visible errors/alerts/validation messages.
|
|
48
|
+
* Deliberately broad (sites use every naming scheme) but every match is
|
|
49
|
+
* length-capped and deduped by the page script.
|
|
50
|
+
*/
|
|
51
|
+
exports.PAGE_ERROR_SELECTORS = [
|
|
52
|
+
'[role="alert"]',
|
|
53
|
+
'[role="status"]',
|
|
54
|
+
'[aria-invalid="true"]',
|
|
55
|
+
'[class*="error"]',
|
|
56
|
+
'[class*="Error"]',
|
|
57
|
+
'[class*="danger"]',
|
|
58
|
+
'[class*="warning"]',
|
|
59
|
+
'[class*="invalid"]',
|
|
60
|
+
'[class*="field-error"]',
|
|
61
|
+
'[class*="form-error"]',
|
|
62
|
+
'[class*="validation-error"]',
|
|
63
|
+
'[class*="error-message"]',
|
|
64
|
+
'.text-red',
|
|
65
|
+
'.text-danger',
|
|
66
|
+
'.text-error',
|
|
67
|
+
'[data-sonner-toast]',
|
|
68
|
+
].join(',');
|
|
69
|
+
/**
|
|
70
|
+
* Build the in-page state script. `includeText` and `maxTextChars` are the only
|
|
71
|
+
* variable parts; the rest is fixed and capped inside the page.
|
|
72
|
+
*/
|
|
73
|
+
function buildPageStateScript(opts = {}) {
|
|
74
|
+
const includeText = opts.includeText !== false;
|
|
75
|
+
const maxText = Math.min(Math.max(Number(opts.maxTextChars) || DEFAULT_TEXT_CAP, 500), 40_000);
|
|
76
|
+
const maxFields = Math.min(Math.max(Number(opts.maxFields) || MAX_FIELDS, 1), 100);
|
|
77
|
+
const errorSelectors = JSON.stringify(exports.PAGE_ERROR_SELECTORS);
|
|
78
|
+
return `
|
|
79
|
+
(() => {
|
|
80
|
+
const MAX_TEXT = ${maxText};
|
|
81
|
+
const MAX_FIELDS = ${maxFields};
|
|
82
|
+
const MAX_DIALOGS = ${MAX_DIALOGS};
|
|
83
|
+
const MAX_ERRORS = ${MAX_ERRORS};
|
|
84
|
+
const MAX_TOASTS = ${MAX_TOASTS};
|
|
85
|
+
const INCLUDE_TEXT = ${includeText ? 'true' : 'false'};
|
|
86
|
+
const ERROR_SEL = ${errorSelectors};
|
|
87
|
+
|
|
88
|
+
const clean = (v, cap) => String(v == null ? '' : v)
|
|
89
|
+
.replace(/\\s+/g, ' ')
|
|
90
|
+
.trim()
|
|
91
|
+
.slice(0, cap || 300);
|
|
92
|
+
const vis = (el) => {
|
|
93
|
+
if (!el || el.nodeType !== 1) return false;
|
|
94
|
+
const r = el.getBoundingClientRect();
|
|
95
|
+
if (r.width === 0 || r.height === 0) return false;
|
|
96
|
+
const cs = getComputedStyle(el);
|
|
97
|
+
return cs.visibility !== 'hidden' && cs.display !== 'none' && cs.opacity !== '0';
|
|
98
|
+
};
|
|
99
|
+
const rect = (el) => {
|
|
100
|
+
const r = el.getBoundingClientRect();
|
|
101
|
+
return {
|
|
102
|
+
x: Math.round(r.x + r.width / 2),
|
|
103
|
+
y: Math.round(r.y + r.height / 2),
|
|
104
|
+
width: Math.round(r.width),
|
|
105
|
+
height: Math.round(r.height),
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
const labelOf = (el) => {
|
|
109
|
+
const aria = el.getAttribute('aria-label');
|
|
110
|
+
if (aria) return clean(aria, 120);
|
|
111
|
+
const by = el.getAttribute('aria-labelledby');
|
|
112
|
+
if (by) {
|
|
113
|
+
const t = by.split(/\\s+/).map((id) => {
|
|
114
|
+
const n = document.getElementById(id);
|
|
115
|
+
return n ? (n.innerText || n.textContent || '') : '';
|
|
116
|
+
}).join(' ');
|
|
117
|
+
if (t.trim()) return clean(t, 120);
|
|
118
|
+
}
|
|
119
|
+
const id = el.id;
|
|
120
|
+
if (id) {
|
|
121
|
+
try {
|
|
122
|
+
const l = document.querySelector('label[for="' + CSS.escape(id) + '"]');
|
|
123
|
+
if (l) return clean(l.innerText || l.textContent, 120);
|
|
124
|
+
} catch (e) {}
|
|
125
|
+
}
|
|
126
|
+
const wrap = el.closest && el.closest('label');
|
|
127
|
+
if (wrap) return clean(wrap.innerText || wrap.textContent, 120);
|
|
128
|
+
return clean(el.getAttribute('placeholder') || el.getAttribute('name') || el.id || '', 120);
|
|
129
|
+
};
|
|
130
|
+
const fieldOf = (el, inDialog) => {
|
|
131
|
+
const r = rect(el);
|
|
132
|
+
const type = String(el.type || el.tagName || '').toLowerCase();
|
|
133
|
+
const valueLength = typeof el.value === 'string' ? el.value.length : 0;
|
|
134
|
+
const invalid = el.getAttribute('aria-invalid') === 'true' ||
|
|
135
|
+
(typeof el.checkValidity === 'function' && !el.checkValidity() && valueLength > 0);
|
|
136
|
+
return {
|
|
137
|
+
tag: String(el.tagName || '').toLowerCase(),
|
|
138
|
+
type: type,
|
|
139
|
+
label: labelOf(el),
|
|
140
|
+
name: clean(el.getAttribute('name') || el.id || '', 80),
|
|
141
|
+
autocomplete: clean(el.getAttribute('autocomplete') || '', 60),
|
|
142
|
+
valueLength: valueLength,
|
|
143
|
+
required: el.required === true,
|
|
144
|
+
invalid: invalid,
|
|
145
|
+
disabled: el.disabled === true,
|
|
146
|
+
readonly: el.readOnly === true,
|
|
147
|
+
focused: document.activeElement === el,
|
|
148
|
+
inDialog: !!inDialog,
|
|
149
|
+
x: r.x,
|
|
150
|
+
y: r.y,
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
const buttonOf = (el) => {
|
|
154
|
+
const r = rect(el);
|
|
155
|
+
return {
|
|
156
|
+
text: clean(el.innerText || el.textContent || el.value || el.getAttribute('aria-label') || '', 100),
|
|
157
|
+
type: clean(el.getAttribute('type') || el.tagName || '', 30).toLowerCase(),
|
|
158
|
+
disabled: el.disabled === true || el.getAttribute('aria-disabled') === 'true',
|
|
159
|
+
x: r.x,
|
|
160
|
+
y: r.y,
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
const zOf = (el) => {
|
|
164
|
+
let z = 0;
|
|
165
|
+
let n = el;
|
|
166
|
+
let guard = 0;
|
|
167
|
+
while (n && n !== document.body && guard++ < 8) {
|
|
168
|
+
const cs = getComputedStyle(n);
|
|
169
|
+
const v = parseInt(cs.zIndex, 10);
|
|
170
|
+
if (!isNaN(v)) z = Math.max(z, v);
|
|
171
|
+
n = n.parentElement;
|
|
172
|
+
}
|
|
173
|
+
return z;
|
|
174
|
+
};
|
|
175
|
+
const dialogSel = 'dialog[open],[role="dialog"],[aria-modal="true"],' +
|
|
176
|
+
'[class*="modal"],[class*="Modal"],[class*="dialog"],[class*="Dialog"]';
|
|
177
|
+
const dialogEls = [...document.querySelectorAll(dialogSel)]
|
|
178
|
+
.filter(vis)
|
|
179
|
+
.slice(0, MAX_DIALOGS);
|
|
180
|
+
const dialogs = dialogEls.map((el, index) => {
|
|
181
|
+
const title =
|
|
182
|
+
clean(el.getAttribute('aria-label') || '', 120) ||
|
|
183
|
+
(() => {
|
|
184
|
+
const by = el.getAttribute('aria-labelledby');
|
|
185
|
+
if (by) {
|
|
186
|
+
const t = by.split(/\\s+/).map((id) => {
|
|
187
|
+
const n = document.getElementById(id);
|
|
188
|
+
return n ? (n.innerText || n.textContent || '') : '';
|
|
189
|
+
}).join(' ');
|
|
190
|
+
if (t.trim()) return clean(t, 120);
|
|
191
|
+
}
|
|
192
|
+
const h = el.querySelector('h1,h2,h3,[class*="title"],[class*="Title"]');
|
|
193
|
+
return h ? clean(h.innerText || h.textContent, 120) : '';
|
|
194
|
+
})();
|
|
195
|
+
const r = rect(el);
|
|
196
|
+
return {
|
|
197
|
+
index: index,
|
|
198
|
+
role: clean(el.getAttribute('role') || (el.tagName || '').toLowerCase(), 30),
|
|
199
|
+
title: title,
|
|
200
|
+
text: clean(el.innerText || el.textContent || '', 1600),
|
|
201
|
+
z: zOf(el),
|
|
202
|
+
x: r.x,
|
|
203
|
+
y: r.y,
|
|
204
|
+
width: r.width,
|
|
205
|
+
height: r.height,
|
|
206
|
+
fields: [...el.querySelectorAll('input,textarea,select')]
|
|
207
|
+
.filter(vis)
|
|
208
|
+
.filter((f) => String(f.type || '').toLowerCase() !== 'hidden')
|
|
209
|
+
.slice(0, MAX_FIELDS)
|
|
210
|
+
.map((f) => fieldOf(f, true)),
|
|
211
|
+
buttons: [...el.querySelectorAll('button,input[type="submit"],input[type="button"],[role="button"],a')]
|
|
212
|
+
.filter(vis)
|
|
213
|
+
.slice(0, 20)
|
|
214
|
+
.map(buttonOf),
|
|
215
|
+
};
|
|
216
|
+
}).sort((a, b) => (a.z - b.z) || (a.index - b.index));
|
|
217
|
+
// Prefer the dialog that actually holds a login field: a cookie banner
|
|
218
|
+
// or a newsletter modal can have a higher z-index, but it is not what
|
|
219
|
+
// the agent is interacting with.
|
|
220
|
+
const loginTop = [...dialogs].reverse().find((d) =>
|
|
221
|
+
d.fields.some(
|
|
222
|
+
(f) =>
|
|
223
|
+
f.type === 'password' ||
|
|
224
|
+
f.type === 'email' ||
|
|
225
|
+
/username|one-time-code|current-password|new-password/.test(
|
|
226
|
+
f.autocomplete || '',
|
|
227
|
+
),
|
|
228
|
+
),
|
|
229
|
+
);
|
|
230
|
+
const top = loginTop ?? (dialogs.length ? dialogs[dialogs.length - 1] : null);
|
|
231
|
+
const topEl = dialogEls[top ? top.index : -1] || null;
|
|
232
|
+
const scope = topEl || document;
|
|
233
|
+
|
|
234
|
+
const fields = (top ? top.fields : [...document.querySelectorAll('input,textarea,select')]
|
|
235
|
+
.slice(0, 200)
|
|
236
|
+
.filter(vis)
|
|
237
|
+
.filter((f) => String(f.type || '').toLowerCase() !== 'hidden')
|
|
238
|
+
.slice(0, MAX_FIELDS)
|
|
239
|
+
.map((f) => fieldOf(f, false)));
|
|
240
|
+
|
|
241
|
+
const errors = [];
|
|
242
|
+
const pushError = (text, role) => {
|
|
243
|
+
const t = clean(text, 240);
|
|
244
|
+
if (t.length < 3) return;
|
|
245
|
+
if (/^(error|errors|warning|warnings)$/i.test(t)) return;
|
|
246
|
+
if (errors.some((e) => e.text === t)) return;
|
|
247
|
+
if (errors.length < MAX_ERRORS) errors.push({ text: t, role: clean(role || '', 30) });
|
|
248
|
+
};
|
|
249
|
+
// Alerts and invalid fields first, then the broad class-based sweep.
|
|
250
|
+
for (const el of [...scope.querySelectorAll('[role="alert"],[aria-invalid="true"]')].filter(vis).slice(0, 4)) {
|
|
251
|
+
pushError(el.innerText || el.textContent || el.getAttribute('aria-label') || '', el.getAttribute('role') || 'invalid');
|
|
252
|
+
}
|
|
253
|
+
for (const el of [...scope.querySelectorAll(ERROR_SEL)].filter(vis).slice(0, 20)) {
|
|
254
|
+
pushError(el.innerText || el.textContent || '', el.getAttribute('role') || 'error');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const toasts = (window.__tsPageEvents || [])
|
|
258
|
+
.filter((e) => e && e.type !== 'dialog' && e.type !== 'dialog-closed')
|
|
259
|
+
.slice(-MAX_TOASTS);
|
|
260
|
+
|
|
261
|
+
const headings = [...document.querySelectorAll('h1,h2,h3')]
|
|
262
|
+
.filter(vis)
|
|
263
|
+
.map((h) => clean(h.innerText || h.textContent || '', 160))
|
|
264
|
+
.filter(Boolean)
|
|
265
|
+
.slice(0, 8);
|
|
266
|
+
|
|
267
|
+
const active = document.activeElement;
|
|
268
|
+
const focused = active && ['input', 'textarea', 'select'].includes(String(active.tagName || '').toLowerCase())
|
|
269
|
+
? {
|
|
270
|
+
tag: String(active.tagName || '').toLowerCase(),
|
|
271
|
+
type: String(active.type || '').toLowerCase(),
|
|
272
|
+
label: labelOf(active),
|
|
273
|
+
valueLength: typeof active.value === 'string' ? active.value.length : 0,
|
|
274
|
+
inDialog: !!(topEl && topEl.contains(active)),
|
|
275
|
+
}
|
|
276
|
+
: null;
|
|
277
|
+
|
|
278
|
+
const busy = [...document.querySelectorAll('[aria-busy="true"],[data-loading="true"],[class*="loading"],[class*="spinner"]')]
|
|
279
|
+
.some(vis);
|
|
280
|
+
|
|
281
|
+
let text = '';
|
|
282
|
+
let textTruncated = false;
|
|
283
|
+
if (INCLUDE_TEXT) {
|
|
284
|
+
const root = document.querySelector('main,article,[role="main"]') || document.body;
|
|
285
|
+
const raw = root ? (root.innerText || root.textContent || '') : '';
|
|
286
|
+
const normalized = raw
|
|
287
|
+
.replace(/\\r/g, '')
|
|
288
|
+
.replace(/[ \\t]+\\n/g, '\\n')
|
|
289
|
+
.replace(/\\n{3,}/g, '\\n\\n')
|
|
290
|
+
.trim();
|
|
291
|
+
textTruncated = normalized.length > MAX_TEXT;
|
|
292
|
+
text = textTruncated ? normalized.slice(0, MAX_TEXT) : normalized;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return {
|
|
296
|
+
url: location.href,
|
|
297
|
+
title: document.title || '',
|
|
298
|
+
readyState: document.readyState || 'unknown',
|
|
299
|
+
headings: headings,
|
|
300
|
+
dialogs: dialogs,
|
|
301
|
+
modal: !!top,
|
|
302
|
+
fields: fields,
|
|
303
|
+
focused: focused,
|
|
304
|
+
errors: errors,
|
|
305
|
+
toasts: toasts,
|
|
306
|
+
busy: busy,
|
|
307
|
+
scroll: { x: Math.round(window.scrollX || 0), y: Math.round(window.scrollY || 0) },
|
|
308
|
+
text: text,
|
|
309
|
+
textTruncated: textTruncated,
|
|
310
|
+
maxTextChars: MAX_TEXT,
|
|
311
|
+
};
|
|
312
|
+
})()
|
|
313
|
+
`;
|
|
314
|
+
}
|
|
315
|
+
function emptyState() {
|
|
316
|
+
return {
|
|
317
|
+
url: '',
|
|
318
|
+
title: '',
|
|
319
|
+
readyState: 'unknown',
|
|
320
|
+
headings: [],
|
|
321
|
+
dialogs: [],
|
|
322
|
+
modal: false,
|
|
323
|
+
fields: [],
|
|
324
|
+
focused: null,
|
|
325
|
+
errors: [],
|
|
326
|
+
toasts: [],
|
|
327
|
+
busy: false,
|
|
328
|
+
scroll: { x: 0, y: 0 },
|
|
329
|
+
text: '',
|
|
330
|
+
textTruncated: false,
|
|
331
|
+
maxTextChars: DEFAULT_TEXT_CAP,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
/** Read the rich page state. Never throws for a malformed page result. */
|
|
335
|
+
async function readPageState(page, opts = {}) {
|
|
336
|
+
const raw = await (0, cdp_1.evaluateJs)(page, buildPageStateScript(opts));
|
|
337
|
+
if (!raw || typeof raw !== 'object')
|
|
338
|
+
return emptyState();
|
|
339
|
+
const r = raw;
|
|
340
|
+
return {
|
|
341
|
+
...emptyState(),
|
|
342
|
+
...r,
|
|
343
|
+
dialogs: Array.isArray(r.dialogs) ? r.dialogs : [],
|
|
344
|
+
fields: Array.isArray(r.fields) ? r.fields : [],
|
|
345
|
+
errors: Array.isArray(r.errors) ? r.errors : [],
|
|
346
|
+
toasts: Array.isArray(r.toasts) ? r.toasts : [],
|
|
347
|
+
headings: Array.isArray(r.headings) ? r.headings : [],
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Bounded state attached to every mutating action result. Keeps the top
|
|
352
|
+
* dialog and its controls, a few errors/toasts and focus - enough for the
|
|
353
|
+
* agent to know what just happened without a second call.
|
|
354
|
+
*/
|
|
355
|
+
function compactPageState(state) {
|
|
356
|
+
const dialogs = state.dialogs.slice(-2).map((d) => ({
|
|
357
|
+
title: d.title,
|
|
358
|
+
role: d.role,
|
|
359
|
+
text: d.text.slice(0, 400),
|
|
360
|
+
fields: d.fields.slice(0, 10),
|
|
361
|
+
buttons: d.buttons.slice(0, 8),
|
|
362
|
+
}));
|
|
363
|
+
return {
|
|
364
|
+
url: state.url,
|
|
365
|
+
title: state.title,
|
|
366
|
+
readyState: state.readyState,
|
|
367
|
+
modal: state.modal,
|
|
368
|
+
dialogs: dialogs,
|
|
369
|
+
fields: state.fields.slice(0, 12),
|
|
370
|
+
focused: state.focused,
|
|
371
|
+
errors: state.errors.slice(0, 4),
|
|
372
|
+
toasts: state.toasts.slice(-4),
|
|
373
|
+
busy: state.busy,
|
|
374
|
+
scroll: state.scroll,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Fast, bounded state for action results and `waitFor` timeouts (2026-10).
|
|
379
|
+
*
|
|
380
|
+
* Deliberately smaller than `buildPageStateScript`: it skips the full page
|
|
381
|
+
* text, all-dialog enumeration, headings and the z-index sort, so attaching it
|
|
382
|
+
* to every click/type/navigate does not slow a QA run down. Still enough to
|
|
383
|
+
* see the top modal, its controls, errors, toasts and focus.
|
|
384
|
+
*/
|
|
385
|
+
function buildCompactStateScript() {
|
|
386
|
+
const errorSelectors = JSON.stringify('[role="alert"],[aria-invalid="true"],[class*="field-error"],[class*="form-error"],[class*="error-message"],[class*="invalid-feedback"],[data-sonner-toast]');
|
|
387
|
+
return `
|
|
388
|
+
(() => {
|
|
389
|
+
const clean = (v, cap) => String(v == null ? '' : v).replace(/\\s+/g, ' ').trim().slice(0, cap || 200);
|
|
390
|
+
const vis = (el) => {
|
|
391
|
+
if (!el || el.nodeType !== 1) return false;
|
|
392
|
+
const r = el.getBoundingClientRect();
|
|
393
|
+
if (r.width === 0 || r.height === 0) return false;
|
|
394
|
+
const cs = getComputedStyle(el);
|
|
395
|
+
return cs.visibility !== 'hidden' && cs.display !== 'none' && cs.opacity !== '0';
|
|
396
|
+
};
|
|
397
|
+
const rect = (el) => {
|
|
398
|
+
const r = el.getBoundingClientRect();
|
|
399
|
+
return { x: Math.round(r.x + r.width / 2), y: Math.round(r.y + r.height / 2) };
|
|
400
|
+
};
|
|
401
|
+
const labelOf = (el) => clean(
|
|
402
|
+
el.getAttribute('aria-label') ||
|
|
403
|
+
el.getAttribute('placeholder') ||
|
|
404
|
+
el.getAttribute('name') ||
|
|
405
|
+
el.id ||
|
|
406
|
+
'',
|
|
407
|
+
100,
|
|
408
|
+
);
|
|
409
|
+
const fieldOf = (el, inDialog) => {
|
|
410
|
+
const r = rect(el);
|
|
411
|
+
return {
|
|
412
|
+
tag: String(el.tagName || '').toLowerCase(),
|
|
413
|
+
type: String(el.type || el.tagName || '').toLowerCase(),
|
|
414
|
+
label: labelOf(el),
|
|
415
|
+
name: clean(el.getAttribute('name') || el.id || '', 80),
|
|
416
|
+
autocomplete: clean(el.getAttribute('autocomplete') || '', 60),
|
|
417
|
+
valueLength: typeof el.value === 'string' ? el.value.length : 0,
|
|
418
|
+
required: el.required === true,
|
|
419
|
+
invalid: el.getAttribute('aria-invalid') === 'true',
|
|
420
|
+
disabled: el.disabled === true,
|
|
421
|
+
readonly: el.readOnly === true,
|
|
422
|
+
focused: document.activeElement === el,
|
|
423
|
+
inDialog: !!inDialog,
|
|
424
|
+
x: r.x,
|
|
425
|
+
y: r.y,
|
|
426
|
+
};
|
|
427
|
+
};
|
|
428
|
+
const buttonOf = (el) => {
|
|
429
|
+
const r = rect(el);
|
|
430
|
+
return {
|
|
431
|
+
text: clean(el.innerText || el.textContent || el.value || el.getAttribute('aria-label') || '', 80),
|
|
432
|
+
type: clean(el.getAttribute('type') || el.tagName || '', 30).toLowerCase(),
|
|
433
|
+
disabled: el.disabled === true || el.getAttribute('aria-disabled') === 'true',
|
|
434
|
+
x: r.x,
|
|
435
|
+
y: r.y,
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
const dialogEls = [...document.querySelectorAll('dialog[open],[role="dialog"],[aria-modal="true"],[class*="modal"],[class*="Modal"],[class*="dialog"],[class*="Dialog"]')]
|
|
439
|
+
.filter(vis)
|
|
440
|
+
.slice(0, 3);
|
|
441
|
+
const loginTop = [...dialogEls].reverse().find((d) =>
|
|
442
|
+
d.querySelector('input[type="password"],input[type="email"],input[autocomplete="username"],input[autocomplete="one-time-code"]'),
|
|
443
|
+
);
|
|
444
|
+
const topEl = loginTop ||
|
|
445
|
+
[...dialogEls].reverse().find((d) => d.querySelector('input,textarea')) ||
|
|
446
|
+
dialogEls[dialogEls.length - 1] ||
|
|
447
|
+
null;
|
|
448
|
+
const top = topEl ? {
|
|
449
|
+
role: clean(topEl.getAttribute('role') || (topEl.tagName || '').toLowerCase(), 30),
|
|
450
|
+
title: clean(
|
|
451
|
+
topEl.getAttribute('aria-label') ||
|
|
452
|
+
(topEl.querySelector('h1,h2,h3') ? topEl.querySelector('h1,h2,h3').innerText : '') ||
|
|
453
|
+
'',
|
|
454
|
+
120,
|
|
455
|
+
),
|
|
456
|
+
text: clean(topEl.innerText || topEl.textContent || '', 300),
|
|
457
|
+
fields: [...topEl.querySelectorAll('input,textarea,select')]
|
|
458
|
+
.filter(vis)
|
|
459
|
+
.filter((f) => String(f.type || '').toLowerCase() !== 'hidden')
|
|
460
|
+
.slice(0, 10)
|
|
461
|
+
.map((f) => fieldOf(f, true)),
|
|
462
|
+
buttons: [...topEl.querySelectorAll('button,input[type="submit"],input[type="button"],[role="button"],a')]
|
|
463
|
+
.filter(vis)
|
|
464
|
+
.slice(0, 8)
|
|
465
|
+
.map(buttonOf),
|
|
466
|
+
} : null;
|
|
467
|
+
const scope = topEl || document;
|
|
468
|
+
const errors = [];
|
|
469
|
+
const pushError = (t, role) => {
|
|
470
|
+
const text = clean(t, 200);
|
|
471
|
+
if (text.length < 3 || errors.length >= 3) return;
|
|
472
|
+
if (/^(error|errors|warning|warnings)$/i.test(text)) return;
|
|
473
|
+
if (!errors.some((e) => e.text === text)) errors.push({ text: text, role: clean(role || '', 24) });
|
|
474
|
+
};
|
|
475
|
+
for (const el of [...scope.querySelectorAll('[role="alert"],[aria-invalid="true"]')].filter(vis).slice(0, 3)) {
|
|
476
|
+
pushError(el.innerText || el.textContent || el.getAttribute('aria-label') || '', el.getAttribute('role') || 'invalid');
|
|
477
|
+
}
|
|
478
|
+
for (const el of [...scope.querySelectorAll(${errorSelectors})].filter(vis).slice(0, 8)) {
|
|
479
|
+
pushError(el.innerText || el.textContent || '', el.getAttribute('role') || 'error');
|
|
480
|
+
}
|
|
481
|
+
const active = document.activeElement;
|
|
482
|
+
const focused = active && ['input', 'textarea', 'select'].includes(String(active.tagName || '').toLowerCase())
|
|
483
|
+
? { tag: String(active.tagName || '').toLowerCase(), type: String(active.type || '').toLowerCase(), label: labelOf(active), valueLength: typeof active.value === 'string' ? active.value.length : 0, inDialog: !!(topEl && topEl.contains(active)) }
|
|
484
|
+
: null;
|
|
485
|
+
return {
|
|
486
|
+
url: location.href,
|
|
487
|
+
title: document.title || '',
|
|
488
|
+
readyState: document.readyState || 'unknown',
|
|
489
|
+
modal: !!topEl,
|
|
490
|
+
dialogs: top ? [top] : [],
|
|
491
|
+
fields: top ? top.fields : [...document.querySelectorAll('input,textarea,select')]
|
|
492
|
+
.slice(0, 120)
|
|
493
|
+
.filter(vis)
|
|
494
|
+
.filter((f) => String(f.type || '').toLowerCase() !== 'hidden')
|
|
495
|
+
.slice(0, 12)
|
|
496
|
+
.map((f) => fieldOf(f, false)),
|
|
497
|
+
focused: focused,
|
|
498
|
+
errors: errors,
|
|
499
|
+
toasts: (window.__tsPageEvents || []).slice(-4),
|
|
500
|
+
busy: [...document.querySelectorAll('[aria-busy="true"],[data-loading="true"],[class*="loading"],[class*="spinner"]')].some(vis),
|
|
501
|
+
scroll: { x: Math.round(window.scrollX || 0), y: Math.round(window.scrollY || 0) },
|
|
502
|
+
};
|
|
503
|
+
})()
|
|
504
|
+
`;
|
|
505
|
+
}
|
|
506
|
+
/** Read the fast compact state; null on a malformed result. */
|
|
507
|
+
async function readCompactState(page) {
|
|
508
|
+
try {
|
|
509
|
+
const raw = await (0, cdp_1.evaluateJs)(page, buildCompactStateScript());
|
|
510
|
+
return raw && typeof raw === 'object'
|
|
511
|
+
? raw
|
|
512
|
+
: null;
|
|
513
|
+
}
|
|
514
|
+
catch {
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
/** Human/LLM-readable rendering of a state (used in `snapshot.summary`). */
|
|
519
|
+
function renderPageStateText(state) {
|
|
520
|
+
const lines = [];
|
|
521
|
+
lines.push(`Title: ${state.title || 'unknown'}`);
|
|
522
|
+
lines.push(`URL: ${state.url || 'unknown'}`);
|
|
523
|
+
if (state.headings.length)
|
|
524
|
+
lines.push(`Headings: ${state.headings.join(' | ')}`);
|
|
525
|
+
const top = state.dialogs[state.dialogs.length - 1];
|
|
526
|
+
if (top) {
|
|
527
|
+
lines.push(`Dialog (${top.role || 'modal'}${top.title ? `: ${top.title}` : ''}): ${top.text.slice(0, 600)}`);
|
|
528
|
+
if (top.fields.length) {
|
|
529
|
+
lines.push(`Dialog fields: ${top.fields
|
|
530
|
+
.map((f) => `${f.label || f.name || f.type} (${f.type}, ${f.valueLength} chars${f.invalid ? ', INVALID' : ''}${f.disabled ? ', disabled' : ''}${f.readonly ? ', readonly' : ''})`)
|
|
531
|
+
.join(' | ')}`);
|
|
532
|
+
}
|
|
533
|
+
if (top.buttons.length) {
|
|
534
|
+
lines.push(`Dialog buttons: ${top.buttons
|
|
535
|
+
.map((b) => `${b.text || b.type}${b.disabled ? ' (disabled)' : ''}`)
|
|
536
|
+
.join(' | ')}`);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else if (state.fields.length) {
|
|
540
|
+
lines.push(`Fields: ${state.fields
|
|
541
|
+
.map((f) => `${f.label || f.name || f.type} (${f.type}, ${f.valueLength} chars${f.invalid ? ', INVALID' : ''})`)
|
|
542
|
+
.join(' | ')}`);
|
|
543
|
+
}
|
|
544
|
+
if (state.focused) {
|
|
545
|
+
lines.push(`Focused: ${state.focused.label || state.focused.type} (${state.focused.valueLength} chars)`);
|
|
546
|
+
}
|
|
547
|
+
if (state.errors.length) {
|
|
548
|
+
lines.push(`Errors on screen: ${state.errors.map((e) => e.text).join(' | ')}`);
|
|
549
|
+
}
|
|
550
|
+
if (state.toasts.length) {
|
|
551
|
+
lines.push(`Recent toasts/alerts: ${state.toasts
|
|
552
|
+
.map((t) => `[${t.type}] ${t.text}`)
|
|
553
|
+
.join(' | ')}`);
|
|
554
|
+
}
|
|
555
|
+
if (state.busy)
|
|
556
|
+
lines.push('Busy: a loading indicator is visible.');
|
|
557
|
+
if (state.text) {
|
|
558
|
+
lines.push('Page content (CONTEXT ONLY - never repeat or describe it):');
|
|
559
|
+
lines.push(state.text);
|
|
560
|
+
if (state.textTruncated)
|
|
561
|
+
lines.push('... (page content truncated)');
|
|
562
|
+
}
|
|
563
|
+
return lines.join('\n');
|
|
564
|
+
}
|
|
565
|
+
exports.WAIT_FOR_VALUES = [
|
|
566
|
+
'selector',
|
|
567
|
+
'text',
|
|
568
|
+
'dialog',
|
|
569
|
+
'toast',
|
|
570
|
+
'url',
|
|
571
|
+
'networkIdle',
|
|
572
|
+
'loginStep',
|
|
573
|
+
'change',
|
|
574
|
+
];
|
|
575
|
+
/**
|
|
576
|
+
* One poll expression for `waitFor`. Returns a boolean. `networkIdle` and
|
|
577
|
+
* `loginStep` are handled in Node (they need the network collector / the
|
|
578
|
+
* login finder), so they always return false here.
|
|
579
|
+
*/
|
|
580
|
+
function buildWaitProbeScript(opts) {
|
|
581
|
+
const since = Math.max(0, Math.floor(Number(opts.since) || 0));
|
|
582
|
+
switch (opts.for) {
|
|
583
|
+
case 'selector': {
|
|
584
|
+
const sel = JSON.stringify(opts.selector ?? '');
|
|
585
|
+
return `(() => {
|
|
586
|
+
const vis = (el) => { if (!el) return false; const r = el.getBoundingClientRect(); if (r.width === 0 || r.height === 0) return false; const cs = getComputedStyle(el); return cs.visibility !== 'hidden' && cs.display !== 'none'; };
|
|
587
|
+
const el = document.querySelector(${sel});
|
|
588
|
+
return !!(el && vis(el));
|
|
589
|
+
})()`;
|
|
590
|
+
}
|
|
591
|
+
case 'text': {
|
|
592
|
+
const needle = JSON.stringify((opts.text ?? '').toLowerCase());
|
|
593
|
+
return `(() => {
|
|
594
|
+
const body = document.body;
|
|
595
|
+
if (!body) return false;
|
|
596
|
+
const t = (body.innerText || body.textContent || '').toLowerCase();
|
|
597
|
+
return t.includes(${needle});
|
|
598
|
+
})()`;
|
|
599
|
+
}
|
|
600
|
+
case 'dialog': {
|
|
601
|
+
const wantClosed = opts.state === 'closed';
|
|
602
|
+
return `(() => {
|
|
603
|
+
const vis = (el) => { if (!el) return false; const r = el.getBoundingClientRect(); if (r.width === 0 || r.height === 0) return false; const cs = getComputedStyle(el); return cs.visibility !== 'hidden' && cs.display !== 'none'; };
|
|
604
|
+
const n = [...document.querySelectorAll('dialog[open],[role="dialog"],[aria-modal="true"]')].filter(vis).length;
|
|
605
|
+
return ${wantClosed ? 'n === 0' : 'n > 0'};
|
|
606
|
+
})()`;
|
|
607
|
+
}
|
|
608
|
+
case 'toast': {
|
|
609
|
+
const needle = JSON.stringify((opts.text ?? '').toLowerCase());
|
|
610
|
+
return `(() => {
|
|
611
|
+
const ev = (window.__tsPageEvents || []).filter((e) => e && e.at >= ${since} &&
|
|
612
|
+
(e.type === 'toast' || e.type === 'alert' || e.type === 'status' || e.type === 'error'));
|
|
613
|
+
const needle = ${needle};
|
|
614
|
+
if (needle) return ev.some((e) => String(e.text || '').toLowerCase().includes(needle));
|
|
615
|
+
return ev.length > 0;
|
|
616
|
+
})()`;
|
|
617
|
+
}
|
|
618
|
+
case 'url': {
|
|
619
|
+
const needle = JSON.stringify(opts.urlIncludes ?? '');
|
|
620
|
+
return `(() => location.href.includes(${needle}))()`;
|
|
621
|
+
}
|
|
622
|
+
case 'change':
|
|
623
|
+
return `(() => !!(window.__tsScreenObs && window.__tsScreenObs.mutated >= ${since}))()`;
|
|
624
|
+
default:
|
|
625
|
+
return 'false';
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
/** Empty snapshot used when the page is blocked by a native dialog. */
|
|
629
|
+
function emptyPageSnapshot(nativeDialog, pendingRequests, consoleErrors = []) {
|
|
630
|
+
return {
|
|
631
|
+
...emptyState(),
|
|
632
|
+
nativeDialog,
|
|
633
|
+
pendingRequests,
|
|
634
|
+
consoleErrors,
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
//# sourceMappingURL=page-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-context.js","sourceRoot":"","sources":["../../../src/lib/browser/page-context.ts"],"names":[],"mappings":"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"}
|