teamshare-bridge 0.26.12 → 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/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/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.d.ts +101 -1
- package/dist/lib/browser/session.js +321 -2
- package/dist/lib/browser/session.js.map +1 -1
- package/dist/lib/orchestrator/handlers/browser.js +200 -31
- package/dist/lib/orchestrator/handlers/browser.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent page-event buffer for the debug browser (2026-10).
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS. The auto-answer browser scrapes toasts/errors at capture
|
|
5
|
+
* time, and the debug browser had NOTHING: a toast that appeared after a form
|
|
6
|
+
* submit and vanished two seconds later was invisible to an agent that only
|
|
7
|
+
* looked on its next tool call. In the live Soludesks QA run the agent spent
|
|
8
|
+
* minutes re-reading the DOM for a dialog/error that had already been shown.
|
|
9
|
+
*
|
|
10
|
+
* This module injects a tiny, idempotent MutationObserver into the page that
|
|
11
|
+
* records toast / alert / status / dialog events in a bounded ring buffer
|
|
12
|
+
* (`window.__tsPageEvents`). It is installed:
|
|
13
|
+
* - immediately when a session connects,
|
|
14
|
+
* - on every new document via `Page.addScriptToEvaluateOnNewDocument`,
|
|
15
|
+
* - again after a main-frame navigation (belt and braces).
|
|
16
|
+
*
|
|
17
|
+
* The script is dependency-free and returns a string so it can be injected
|
|
18
|
+
* with `Runtime.evaluate` or registered as a new-document script. It never
|
|
19
|
+
* reads field values and never logs anything.
|
|
20
|
+
*/
|
|
21
|
+
/** Maximum events retained in the page ring buffer (oldest dropped). */
|
|
22
|
+
export declare const PAGE_EVENT_LIMIT = 80;
|
|
23
|
+
export interface PageEvent {
|
|
24
|
+
/** toast | alert | status | error | dialog | dialog-closed */
|
|
25
|
+
type: string;
|
|
26
|
+
text: string;
|
|
27
|
+
/** epoch ms, page clock */
|
|
28
|
+
at: number;
|
|
29
|
+
role?: string;
|
|
30
|
+
count?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build the injected page-event script.
|
|
34
|
+
*
|
|
35
|
+
* IMPORTANT: regex escapes must be DOUBLE-escaped inside this template literal
|
|
36
|
+
* (`\\s`), otherwise the injected JS receives `s` (the exact bug the bridge lint
|
|
37
|
+
* gate found in another injected script).
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildPageEventScript(): string;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Persistent page-event buffer for the debug browser (2026-10).
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. The auto-answer browser scrapes toasts/errors at capture
|
|
6
|
+
* time, and the debug browser had NOTHING: a toast that appeared after a form
|
|
7
|
+
* submit and vanished two seconds later was invisible to an agent that only
|
|
8
|
+
* looked on its next tool call. In the live Soludesks QA run the agent spent
|
|
9
|
+
* minutes re-reading the DOM for a dialog/error that had already been shown.
|
|
10
|
+
*
|
|
11
|
+
* This module injects a tiny, idempotent MutationObserver into the page that
|
|
12
|
+
* records toast / alert / status / dialog events in a bounded ring buffer
|
|
13
|
+
* (`window.__tsPageEvents`). It is installed:
|
|
14
|
+
* - immediately when a session connects,
|
|
15
|
+
* - on every new document via `Page.addScriptToEvaluateOnNewDocument`,
|
|
16
|
+
* - again after a main-frame navigation (belt and braces).
|
|
17
|
+
*
|
|
18
|
+
* The script is dependency-free and returns a string so it can be injected
|
|
19
|
+
* with `Runtime.evaluate` or registered as a new-document script. It never
|
|
20
|
+
* reads field values and never logs anything.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.PAGE_EVENT_LIMIT = void 0;
|
|
24
|
+
exports.buildPageEventScript = buildPageEventScript;
|
|
25
|
+
/** Maximum events retained in the page ring buffer (oldest dropped). */
|
|
26
|
+
exports.PAGE_EVENT_LIMIT = 80;
|
|
27
|
+
/**
|
|
28
|
+
* Build the injected page-event script.
|
|
29
|
+
*
|
|
30
|
+
* IMPORTANT: regex escapes must be DOUBLE-escaped inside this template literal
|
|
31
|
+
* (`\\s`), otherwise the injected JS receives `s` (the exact bug the bridge lint
|
|
32
|
+
* gate found in another injected script).
|
|
33
|
+
*/
|
|
34
|
+
function buildPageEventScript() {
|
|
35
|
+
return `
|
|
36
|
+
(() => {
|
|
37
|
+
if (window.__tsEventInstalled) return 'already';
|
|
38
|
+
window.__tsEventInstalled = true;
|
|
39
|
+
const MAX = ${exports.PAGE_EVENT_LIMIT};
|
|
40
|
+
const events = [];
|
|
41
|
+
window.__tsPageEvents = events;
|
|
42
|
+
const clean = (v) => String(v == null ? '' : v).replace(/\\s+/g, ' ').trim().slice(0, 500);
|
|
43
|
+
const now = () => Date.now();
|
|
44
|
+
const vis = (el) => {
|
|
45
|
+
if (!el || el.nodeType !== 1) return false;
|
|
46
|
+
const r = el.getBoundingClientRect();
|
|
47
|
+
if (r.width === 0 || r.height === 0) return false;
|
|
48
|
+
const cs = getComputedStyle(el);
|
|
49
|
+
return cs.visibility !== 'hidden' && cs.display !== 'none' && cs.opacity !== '0';
|
|
50
|
+
};
|
|
51
|
+
const push = (type, text, extra) => {
|
|
52
|
+
const t = clean(text);
|
|
53
|
+
if (!t || t.length < 2) return;
|
|
54
|
+
const last = events[events.length - 1];
|
|
55
|
+
if (last && last.type === type && last.text === t && now() - last.at < 1200) return;
|
|
56
|
+
const row = { type: type, text: t, at: now() };
|
|
57
|
+
if (extra) { if (extra.role) row.role = extra.role; if (extra.count != null) row.count = extra.count; }
|
|
58
|
+
events.push(row);
|
|
59
|
+
if (events.length > MAX) events.splice(0, events.length - MAX);
|
|
60
|
+
};
|
|
61
|
+
const TOAST_SEL = '[role="alert"],[role="status"],[aria-live],[data-sonner-toast],' +
|
|
62
|
+
'[class*="toast"],[class*="Toast"],[class*="snackbar"],[class*="Snackbar"],' +
|
|
63
|
+
'[class*="notification"],[class*="Notification"],[class*="alert"],[class*="Alert"],' +
|
|
64
|
+
'[class*="banner"],[class*="Banner"]';
|
|
65
|
+
const kindOf = (el) => {
|
|
66
|
+
const role = String((el.getAttribute && el.getAttribute('role')) || '').toLowerCase();
|
|
67
|
+
const cls = String((el.className && typeof el.className === 'string') ? el.className : '') + ' ' + String(el.id || '');
|
|
68
|
+
const live = String((el.getAttribute && el.getAttribute('aria-live')) || '').toLowerCase();
|
|
69
|
+
if (role === 'alert' || /error|danger|invalid/i.test(cls)) return 'error';
|
|
70
|
+
if (/toast|snackbar|notification/i.test(cls)) return 'toast';
|
|
71
|
+
if (role === 'status' || live === 'polite' || live === 'assertive') return 'status';
|
|
72
|
+
if (/alert|banner/i.test(cls)) return 'alert';
|
|
73
|
+
return null;
|
|
74
|
+
};
|
|
75
|
+
const record = (el) => {
|
|
76
|
+
if (!el || el.nodeType !== 1 || !vis(el)) return;
|
|
77
|
+
// A container that holds a nested toast should not be recorded as a
|
|
78
|
+
// second, duplicate event; use the deepest matching node.
|
|
79
|
+
const nested = el.querySelector && el.querySelector(TOAST_SEL);
|
|
80
|
+
if (nested && nested !== el) return;
|
|
81
|
+
const kind = kindOf(el);
|
|
82
|
+
if (!kind) return;
|
|
83
|
+
const text = el.innerText || el.textContent || el.getAttribute('aria-label') || '';
|
|
84
|
+
push(kind, text, { role: String((el.getAttribute && el.getAttribute('role')) || '') });
|
|
85
|
+
};
|
|
86
|
+
const scan = (root) => {
|
|
87
|
+
if (!root || root.nodeType !== 1) return;
|
|
88
|
+
if (root.matches && root.matches(TOAST_SEL)) record(root);
|
|
89
|
+
if (root.querySelectorAll) {
|
|
90
|
+
const nodes = root.querySelectorAll(TOAST_SEL);
|
|
91
|
+
for (let i = 0; i < nodes.length && i < 12; i++) record(nodes[i]);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
const dialogs = () => [...document.querySelectorAll('dialog[open],[role="dialog"],[aria-modal="true"]')].filter(vis);
|
|
95
|
+
let dialogCount = dialogs().length;
|
|
96
|
+
const topDialogText = () => {
|
|
97
|
+
const list = dialogs();
|
|
98
|
+
const el = list[list.length - 1];
|
|
99
|
+
return el ? clean(el.innerText || el.textContent || '') : '';
|
|
100
|
+
};
|
|
101
|
+
const obs = new MutationObserver((mutations) => {
|
|
102
|
+
for (const m of mutations) {
|
|
103
|
+
if (m.type === 'childList') {
|
|
104
|
+
for (const n of m.addedNodes) if (n && n.nodeType === 1) scan(n);
|
|
105
|
+
} else if (m.type === 'characterData') {
|
|
106
|
+
const p = m.target && m.target.parentElement;
|
|
107
|
+
if (p) scan(p);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const count = dialogs().length;
|
|
111
|
+
if (count !== dialogCount) {
|
|
112
|
+
if (count > 0) push('dialog', topDialogText(), { count: count });
|
|
113
|
+
else push('dialog-closed', 'dialog closed', { count: 0 });
|
|
114
|
+
dialogCount = count;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const root = document.documentElement || document.body;
|
|
118
|
+
if (root) {
|
|
119
|
+
obs.observe(root, { childList: true, subtree: true, characterData: true });
|
|
120
|
+
// Record anything already on screen once (a login modal that opened
|
|
121
|
+
// before this script ran).
|
|
122
|
+
scan(document.body || root);
|
|
123
|
+
}
|
|
124
|
+
return 'ok';
|
|
125
|
+
})()
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=page-events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-events.js","sourceRoot":"","sources":["../../../src/lib/browser/page-events.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;;;AAsBH,oDA6FC;AAjHD,wEAAwE;AAC3D,QAAA,gBAAgB,GAAG,EAAE,CAAC;AAYnC;;;;;;GAMG;AACH,SAAgB,oBAAoB;IAClC,OAAO;;;;oBAIW,wBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFjC,CAAC;AACJ,CAAC"}
|
|
@@ -117,6 +117,9 @@ function buildObserverScript() {
|
|
|
117
117
|
});
|
|
118
118
|
lastText = getText();
|
|
119
119
|
window[KEY] = { observer: obs, changed: 0, mutated: 0 };
|
|
120
|
+
// String-addressable alias for OTHER injected scripts (the debug
|
|
121
|
+
// browser's waitFor reads it; a Symbol is not reachable by name).
|
|
122
|
+
window.__tsScreenObs = window[KEY];
|
|
120
123
|
obs.observe(document.body || document.documentElement, {
|
|
121
124
|
childList: true, subtree: true, characterData: true
|
|
122
125
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"screen-change.js","sourceRoot":"","sources":["../../../src/lib/browser/screen-change.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAcH,kDAkBC;AAOD,sDAIC;AAQD,
|
|
1
|
+
{"version":3,"file":"screen-change.js","sourceRoot":"","sources":["../../../src/lib/browser/screen-change.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAcH,kDAkBC;AAOD,sDAIC;AAQD,kDAiEC;AAlHD,0EAA0E;AAC7D,QAAA,uBAAuB,GAAG,EAAE,CAAC;AAE1C;;;;;;;;GAQG;AACH,SAAgB,mBAAmB,CACjC,QAAgB,EAChB,QAAgB;IAEhB,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACxE,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,IAAI,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,MAAM;gBAAE,OAAO,EAAE,CAAC;;gBACpD,OAAO,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC/D,OAAO,KAAK,GAAG,EAAE,GAAG,OAAO,GAAG,EAAE,GAAG,OAAO,GAAG,CAAC,CAAC;AACjD,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CACnC,MAA4D;IAE5D,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,mBAAmB;IACjC,OAAO;;;;;sCAK6B,mBAAmB,CAAC,QAAQ,EAAE;;;;;;;;;;;;;;;;qDAgBf,+BAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0CvE,CAAC;AACN,CAAC"}
|
|
@@ -2,6 +2,8 @@ import type { CdpPage, ElementInfo, PageInfo, PageText, PageLink } from './cdp';
|
|
|
2
2
|
import { type NetworkEntry, type ConsoleEntry } from './network-log';
|
|
3
3
|
import { type ReadStagedResult, type FillExcelResult } from './xlsx-template';
|
|
4
4
|
import { type LoginResult, type PerformLoginOptions } from './login';
|
|
5
|
+
import { type NativeDialogState, type PageSnapshot, type WaitForKind } from './page-context';
|
|
6
|
+
import { type PageEvent } from './page-events';
|
|
5
7
|
/**
|
|
6
8
|
* Persistent Chrome profile for the AUTO-ANSWER browser (research reads,
|
|
7
9
|
* `browse --auto-answer`, the web-auto-answer tool).
|
|
@@ -78,6 +80,13 @@ export declare class BrowserSession {
|
|
|
78
80
|
* { action: "networkLog" }` when it needs to prove an API mismatch.
|
|
79
81
|
*/
|
|
80
82
|
private network;
|
|
83
|
+
/**
|
|
84
|
+
* The native alert/confirm/prompt/beforeunload currently blocking the page
|
|
85
|
+
* (2026-10). Captured from `Page.javascriptDialogOpening`; other actions are
|
|
86
|
+
* refused while it is set, and `browser_action({action:"dialog"})` resolves
|
|
87
|
+
* it. A native dialog blocks the renderer, so a page snapshot would hang.
|
|
88
|
+
*/
|
|
89
|
+
private _nativeDialog;
|
|
81
90
|
constructor(id: string, opts?: BrowserSessionOptions);
|
|
82
91
|
/** The stable session name the browser manager keys this session by. */
|
|
83
92
|
get sessionKey(): string;
|
|
@@ -99,6 +108,8 @@ export declare class BrowserSession {
|
|
|
99
108
|
*/
|
|
100
109
|
setAllowCredentials(allow: boolean): void;
|
|
101
110
|
get allowCredentials(): boolean;
|
|
111
|
+
/** The native JS dialog currently blocking the page, if any. */
|
|
112
|
+
get nativeDialog(): NativeDialogState | null;
|
|
102
113
|
/** Last time a command actually used this session (drives idle close). */
|
|
103
114
|
private _lastUsedAt;
|
|
104
115
|
/** When this session was last used — the idle-close timer reads this. */
|
|
@@ -133,6 +144,37 @@ export declare class BrowserSession {
|
|
|
133
144
|
* Connect to a specific tab by targetId.
|
|
134
145
|
*/
|
|
135
146
|
connectToTab(targetId: string): Promise<PageInfo>;
|
|
147
|
+
/**
|
|
148
|
+
* Install the debug browser's page instrumentation (2026-10):
|
|
149
|
+
*
|
|
150
|
+
* - the persistent toast/alert/dialog ring buffer (`page-events.ts`),
|
|
151
|
+
* registered for FUTURE documents via
|
|
152
|
+
* `Page.addScriptToEvaluateOnNewDocument` and injected into the current
|
|
153
|
+
* one immediately;
|
|
154
|
+
* - the screen-change observer (`__tsScreenObs.mutated`) so `waitFor
|
|
155
|
+
* {for:"change"}` knows a click had an effect without a blind sleep;
|
|
156
|
+
* - the native-dialog listener (`Page.javascriptDialogOpening`), because an
|
|
157
|
+
* alert/confirm/prompt blocks the renderer and must be surfaced and
|
|
158
|
+
* resolved explicitly.
|
|
159
|
+
*
|
|
160
|
+
* All pieces are idempotent in the page. The CDP listeners are bound once per
|
|
161
|
+
* page object (a reconnect creates a new one).
|
|
162
|
+
*/
|
|
163
|
+
private instrumentPage;
|
|
164
|
+
/**
|
|
165
|
+
* Resolve a native JS dialog (alert/confirm/prompt/beforeunload).
|
|
166
|
+
* `accept:false` dismisses it; `promptText` is used by a prompt.
|
|
167
|
+
*/
|
|
168
|
+
dialogAction(opts: {
|
|
169
|
+
accept?: boolean;
|
|
170
|
+
promptText?: string;
|
|
171
|
+
}): Promise<{
|
|
172
|
+
ok: boolean;
|
|
173
|
+
accepted?: boolean;
|
|
174
|
+
type?: string;
|
|
175
|
+
message?: string;
|
|
176
|
+
error?: string;
|
|
177
|
+
}>;
|
|
136
178
|
/**
|
|
137
179
|
* Navigate to a URL. Returns page info after navigation.
|
|
138
180
|
*/
|
|
@@ -167,7 +209,9 @@ export declare class BrowserSession {
|
|
|
167
209
|
* credential for the run - the debug browser is the QA surface, the
|
|
168
210
|
* auto-answer loop is a separate path that still never touches credentials.
|
|
169
211
|
*/
|
|
170
|
-
type(text: string
|
|
212
|
+
type(text: string, opts?: {
|
|
213
|
+
clearFirst?: boolean;
|
|
214
|
+
}): Promise<void>;
|
|
171
215
|
/**
|
|
172
216
|
* Deterministically fill a login form (username + password) and submit.
|
|
173
217
|
* Handles the common two-step email -> Continue -> password flow. Requires
|
|
@@ -311,6 +355,62 @@ export declare class BrowserSession {
|
|
|
311
355
|
* Get current page info.
|
|
312
356
|
*/
|
|
313
357
|
pageInfo(): Promise<PageInfo>;
|
|
358
|
+
/**
|
|
359
|
+
* Full page state (2026-10): dialogs (topmost with buttons/fields), toasts
|
|
360
|
+
* (persistent buffer), visible errors, form fields (lengths only), focus,
|
|
361
|
+
* busy, headings, optional page text, pending requests and console errors.
|
|
362
|
+
*
|
|
363
|
+
* This is the debug browser's equivalent of the auto-answer loop's rich
|
|
364
|
+
* `extractPageContext` - and it is what lets an agent see a login modal
|
|
365
|
+
* instead of guessing with raw `evaluate`.
|
|
366
|
+
*/
|
|
367
|
+
snapshot(opts?: {
|
|
368
|
+
includeText?: boolean;
|
|
369
|
+
maxTextChars?: number;
|
|
370
|
+
maxFields?: number;
|
|
371
|
+
}): Promise<PageSnapshot>;
|
|
372
|
+
/**
|
|
373
|
+
* Bounded state attached to every mutating action result. Never include the
|
|
374
|
+
* page text (that is what `snapshot` is for); a failure returns null so an
|
|
375
|
+
* action result is never failed by its own observation.
|
|
376
|
+
*/
|
|
377
|
+
compactSnapshot(): Promise<Record<string, unknown> | null>;
|
|
378
|
+
/**
|
|
379
|
+
* Recent toast / alert / dialog events from the persistent page buffer.
|
|
380
|
+
* This is how a toast that disappeared before the next tool call is still
|
|
381
|
+
* visible.
|
|
382
|
+
*/
|
|
383
|
+
events(opts?: {
|
|
384
|
+
limit?: number;
|
|
385
|
+
clear?: boolean;
|
|
386
|
+
since?: number;
|
|
387
|
+
}): Promise<{
|
|
388
|
+
events: PageEvent[];
|
|
389
|
+
count: number;
|
|
390
|
+
}>;
|
|
391
|
+
/**
|
|
392
|
+
* Wait until a page condition is true, then return the current screen.
|
|
393
|
+
*
|
|
394
|
+
* This replaces the manual `evaluate` polling loop the QA agent used to run
|
|
395
|
+
* (and which broke on "Inspected target navigated"). On timeout it returns
|
|
396
|
+
* `matched:false` WITH the current screen, so the caller can see why.
|
|
397
|
+
*/
|
|
398
|
+
waitFor(opts: {
|
|
399
|
+
for: WaitForKind;
|
|
400
|
+
selector?: string;
|
|
401
|
+
text?: string;
|
|
402
|
+
urlIncludes?: string;
|
|
403
|
+
state?: 'open' | 'closed';
|
|
404
|
+
loginPhase?: 'username' | 'password' | 'otp' | 'done';
|
|
405
|
+
timeoutMs?: number;
|
|
406
|
+
pollMs?: number;
|
|
407
|
+
}): Promise<{
|
|
408
|
+
matched: boolean;
|
|
409
|
+
elapsedMs: number;
|
|
410
|
+
for: WaitForKind;
|
|
411
|
+
screen: Record<string, unknown> | null;
|
|
412
|
+
nativeDialog: NativeDialogState | null;
|
|
413
|
+
}>;
|
|
314
414
|
/**
|
|
315
415
|
* Is the page actually usable right now? (2026-10)
|
|
316
416
|
*
|