@framers/agentos-ext-browser-automation 0.1.0 → 0.2.1
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/README.md +80 -0
- package/dist/BrowserService.js +9 -45
- package/dist/BrowserService.js.map +1 -1
- package/dist/attach/AttachController.d.ts +183 -0
- package/dist/attach/AttachController.d.ts.map +1 -0
- package/dist/attach/AttachController.js +286 -0
- package/dist/attach/AttachController.js.map +1 -0
- package/dist/attach/backends/jxa.d.ts +39 -0
- package/dist/attach/backends/jxa.d.ts.map +1 -0
- package/dist/attach/backends/jxa.js +155 -0
- package/dist/attach/backends/jxa.js.map +1 -0
- package/dist/attach/backends/raw-cdp.d.ts +53 -0
- package/dist/attach/backends/raw-cdp.d.ts.map +1 -0
- package/dist/attach/backends/raw-cdp.js +213 -0
- package/dist/attach/backends/raw-cdp.js.map +1 -0
- package/dist/attach/daemon/client.d.ts +64 -0
- package/dist/attach/daemon/client.d.ts.map +1 -0
- package/dist/attach/daemon/client.js +120 -0
- package/dist/attach/daemon/client.js.map +1 -0
- package/dist/attach/daemon/daemon-lock.d.ts +19 -0
- package/dist/attach/daemon/daemon-lock.d.ts.map +1 -0
- package/dist/attach/daemon/daemon-lock.js +84 -0
- package/dist/attach/daemon/daemon-lock.js.map +1 -0
- package/dist/attach/daemon/daemon-main.d.ts +17 -0
- package/dist/attach/daemon/daemon-main.d.ts.map +1 -0
- package/dist/attach/daemon/daemon-main.js +99 -0
- package/dist/attach/daemon/daemon-main.js.map +1 -0
- package/dist/attach/daemon/daemon.d.ts +52 -0
- package/dist/attach/daemon/daemon.d.ts.map +1 -0
- package/dist/attach/daemon/daemon.js +273 -0
- package/dist/attach/daemon/daemon.js.map +1 -0
- package/dist/attach/daemon/index.d.ts +12 -0
- package/dist/attach/daemon/index.d.ts.map +1 -0
- package/dist/attach/daemon/index.js +12 -0
- package/dist/attach/daemon/index.js.map +1 -0
- package/dist/attach/daemon/protocol.d.ts +69 -0
- package/dist/attach/daemon/protocol.d.ts.map +1 -0
- package/dist/attach/daemon/protocol.js +96 -0
- package/dist/attach/daemon/protocol.js.map +1 -0
- package/dist/attach/daemon/runner.d.ts +64 -0
- package/dist/attach/daemon/runner.d.ts.map +1 -0
- package/dist/attach/daemon/runner.js +57 -0
- package/dist/attach/daemon/runner.js.map +1 -0
- package/dist/attach/daemon/surface.d.ts +31 -0
- package/dist/attach/daemon/surface.d.ts.map +1 -0
- package/dist/attach/daemon/surface.js +87 -0
- package/dist/attach/daemon/surface.js.map +1 -0
- package/dist/attach/devtools-port.d.ts +37 -0
- package/dist/attach/devtools-port.d.ts.map +1 -0
- package/dist/attach/devtools-port.js +47 -0
- package/dist/attach/devtools-port.js.map +1 -0
- package/dist/attach/errors.d.ts +38 -0
- package/dist/attach/errors.d.ts.map +1 -0
- package/dist/attach/errors.js +67 -0
- package/dist/attach/errors.js.map +1 -0
- package/dist/attach/lease.d.ts +43 -0
- package/dist/attach/lease.d.ts.map +1 -0
- package/dist/attach/lease.js +87 -0
- package/dist/attach/lease.js.map +1 -0
- package/dist/attach/singleton-lock.d.ts +21 -0
- package/dist/attach/singleton-lock.d.ts.map +1 -0
- package/dist/attach/singleton-lock.js +27 -0
- package/dist/attach/singleton-lock.js.map +1 -0
- package/dist/attach/state.d.ts +31 -0
- package/dist/attach/state.d.ts.map +1 -0
- package/dist/attach/state.js +71 -0
- package/dist/attach/state.js.map +1 -0
- package/dist/attach/tools.d.ts +208 -0
- package/dist/attach/tools.d.ts.map +1 -0
- package/dist/attach/tools.js +191 -0
- package/dist/attach/tools.js.map +1 -0
- package/dist/attach/url-policy.d.ts +41 -0
- package/dist/attach/url-policy.d.ts.map +1 -0
- package/dist/attach/url-policy.js +55 -0
- package/dist/attach/url-policy.js.map +1 -0
- package/dist/attach.d.ts +18 -0
- package/dist/attach.d.ts.map +1 -0
- package/dist/attach.js +18 -0
- package/dist/attach.js.map +1 -0
- package/dist/captcha/CaptchaSolver.js +4 -7
- package/dist/captcha/CaptchaSolver.js.map +1 -1
- package/dist/captcha/ICaptchaProvider.js +1 -2
- package/dist/captcha/ICaptchaProvider.js.map +1 -1
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -65
- package/dist/index.js.map +1 -1
- package/dist/proxy/IProxyProvider.js +1 -2
- package/dist/proxy/IProxyProvider.js.map +1 -1
- package/dist/proxy/ProxyManager.js +7 -10
- package/dist/proxy/ProxyManager.js.map +1 -1
- package/dist/tools/ClickTool.js +17 -20
- package/dist/tools/ClickTool.js.map +1 -1
- package/dist/tools/EvaluateTool.js +16 -19
- package/dist/tools/EvaluateTool.js.map +1 -1
- package/dist/tools/ExtractTool.js +23 -26
- package/dist/tools/ExtractTool.js.map +1 -1
- package/dist/tools/FillTool.js +17 -20
- package/dist/tools/FillTool.js.map +1 -1
- package/dist/tools/NavigateTool.js +31 -34
- package/dist/tools/NavigateTool.js.map +1 -1
- package/dist/tools/PageSnapshotTool.js +13 -16
- package/dist/tools/PageSnapshotTool.js.map +1 -1
- package/dist/tools/ScreenshotTool.js +16 -19
- package/dist/tools/ScreenshotTool.js.map +1 -1
- package/dist/tools/ScrollTool.js +17 -20
- package/dist/tools/ScrollTool.js.map +1 -1
- package/dist/tools/SessionTool.js +24 -27
- package/dist/tools/SessionTool.js.map +1 -1
- package/dist/tools/WaitTool.js +22 -25
- package/dist/tools/WaitTool.js.map +1 -1
- package/manifest.json +1 -1
- package/package.json +23 -7
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Raw-CDP attach backend over Node's built-in WebSocket.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the playwright `connectOverCDP` backend, which live-failed against
|
|
5
|
+
* a ~29-tab daily Chrome (whole-browser attach enumerates every tab and hangs)
|
|
6
|
+
* and used the `127.0.0.1` host Chrome's DNS-rebinding guard 403s. This
|
|
7
|
+
* backend opens ONE ws to the browser endpoint (host `localhost`, from
|
|
8
|
+
* `DevToolsActivePort`), creates ONE agent tab, attaches flattened to that
|
|
9
|
+
* single target, and can close only that tab. Requires Node >= 22 (built-in
|
|
10
|
+
* `WebSocket`); `daemon-main` guards this at startup.
|
|
11
|
+
*
|
|
12
|
+
* @module browser-automation/attach/backends/raw-cdp
|
|
13
|
+
*/
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
import { homedir } from 'node:os';
|
|
16
|
+
import { join } from 'node:path';
|
|
17
|
+
import { AttachError } from '../errors.js';
|
|
18
|
+
import { parseDevToolsActivePort } from '../devtools-port.js';
|
|
19
|
+
const DEFAULT_PROFILE_ROOT = join(homedir(), 'Library', 'Application Support', 'Google', 'Chrome');
|
|
20
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21
|
+
/**
|
|
22
|
+
* Raw single-target CDP backend (see fileoverview for the contract).
|
|
23
|
+
*
|
|
24
|
+
* Never sends `Browser.close`; `Target.closeTarget` is only ever issued for
|
|
25
|
+
* the tab this instance created.
|
|
26
|
+
*/
|
|
27
|
+
export class RawCdpBackend {
|
|
28
|
+
kind = 'cdp';
|
|
29
|
+
opts;
|
|
30
|
+
ws = null;
|
|
31
|
+
nextId = 0;
|
|
32
|
+
pending = new Map();
|
|
33
|
+
sessionId = null;
|
|
34
|
+
createdTargetId = null;
|
|
35
|
+
/** Invoked once when the transport drops unexpectedly (daemon schedules backoff reconnect). */
|
|
36
|
+
onUnexpectedClose = null;
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.opts = {
|
|
39
|
+
profileRoot: options.profileRoot ?? DEFAULT_PROFILE_ROOT,
|
|
40
|
+
identityProbeUrl: options.identityProbeUrl ?? 'mail.google.com',
|
|
41
|
+
settleMs: options.settleMs ?? 1800,
|
|
42
|
+
commandTimeoutMs: options.commandTimeoutMs ?? 20_000,
|
|
43
|
+
connectTimeoutMs: options.connectTimeoutMs ?? 15_000,
|
|
44
|
+
evalMaxChars: options.evalMaxChars ?? 512 * 1024,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Open the ws to the browser endpoint. Creates/focuses NOTHING. Idempotent while connected. */
|
|
48
|
+
async connect() {
|
|
49
|
+
if (this.ws)
|
|
50
|
+
return;
|
|
51
|
+
let raw;
|
|
52
|
+
try {
|
|
53
|
+
raw = readFileSync(join(this.opts.profileRoot, 'DevToolsActivePort'), 'utf8');
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
throw new AttachError('CDP_UNAVAILABLE', 'DevToolsActivePort absent — remote debugging is not enabled on the target browser');
|
|
57
|
+
}
|
|
58
|
+
let wsUrl;
|
|
59
|
+
try {
|
|
60
|
+
wsUrl = parseDevToolsActivePort(raw).wsUrl;
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new AttachError('STALE_PORT_FILE', `DevToolsActivePort unusable: ${err.message}`);
|
|
64
|
+
}
|
|
65
|
+
const ws = new WebSocket(wsUrl);
|
|
66
|
+
ws.addEventListener('message', (ev) => this.onMessage(String(ev.data)));
|
|
67
|
+
await new Promise((resolve, reject) => {
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
try {
|
|
70
|
+
ws.close();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
/* already dead */
|
|
74
|
+
}
|
|
75
|
+
reject(new AttachError('CDP_TIMEOUT', `ws open timed out after ${this.opts.connectTimeoutMs}ms`));
|
|
76
|
+
}, this.opts.connectTimeoutMs);
|
|
77
|
+
ws.addEventListener('open', () => {
|
|
78
|
+
clearTimeout(timer);
|
|
79
|
+
resolve();
|
|
80
|
+
}, { once: true });
|
|
81
|
+
ws.addEventListener('error', () => {
|
|
82
|
+
clearTimeout(timer);
|
|
83
|
+
reject(new AttachError('CDP_UNAVAILABLE', 'ws connection refused or failed'));
|
|
84
|
+
}, { once: true });
|
|
85
|
+
});
|
|
86
|
+
// Persistent drop handlers attach only AFTER a successful open, so a refused
|
|
87
|
+
// connection rejects connect() without also firing onUnexpectedClose.
|
|
88
|
+
this.ws = ws;
|
|
89
|
+
ws.addEventListener('close', () => this.failAllPending('transport closed'));
|
|
90
|
+
ws.addEventListener('error', () => this.failAllPending('transport error'));
|
|
91
|
+
}
|
|
92
|
+
/** Close ONLY our created tab (if any), then the ws. Never `Browser.close`. */
|
|
93
|
+
async disconnectTransport() {
|
|
94
|
+
if (this.ws && this.createdTargetId) {
|
|
95
|
+
await this.send('Target.closeTarget', { targetId: this.createdTargetId }).catch(() => {
|
|
96
|
+
/* tab may already be gone */
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
this.createdTargetId = null;
|
|
100
|
+
this.sessionId = null;
|
|
101
|
+
const ws = this.ws;
|
|
102
|
+
this.ws = null; // cleared FIRST so the close listener cannot report an unexpected drop
|
|
103
|
+
if (ws) {
|
|
104
|
+
try {
|
|
105
|
+
ws.close();
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* already closed */
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Create the agent tab, attach flattened to it alone, enable Page/Runtime on that session only. */
|
|
113
|
+
async claimAgentTab() {
|
|
114
|
+
const created = (await this.send('Target.createTarget', { url: 'about:blank' }));
|
|
115
|
+
this.createdTargetId = created.targetId;
|
|
116
|
+
const attached = (await this.send('Target.attachToTarget', {
|
|
117
|
+
targetId: created.targetId,
|
|
118
|
+
flatten: true,
|
|
119
|
+
}));
|
|
120
|
+
this.sessionId = attached.sessionId;
|
|
121
|
+
await this.send('Page.enable', {}, this.sessionId);
|
|
122
|
+
await this.send('Runtime.enable', {}, this.sessionId);
|
|
123
|
+
return created.targetId;
|
|
124
|
+
}
|
|
125
|
+
/** Metadata-only identity read: matching page targets' titles/urls. No attach, no navigation. */
|
|
126
|
+
async probeIdentity() {
|
|
127
|
+
const { targetInfos } = (await this.send('Target.getTargets'));
|
|
128
|
+
return targetInfos
|
|
129
|
+
.filter((t) => t.type === 'page' && t.url.includes(this.opts.identityProbeUrl))
|
|
130
|
+
.map((t) => `${t.title} ${t.url}`)
|
|
131
|
+
.join(' | ');
|
|
132
|
+
}
|
|
133
|
+
/** Navigate the agent tab, settle, return the landed URL. */
|
|
134
|
+
async gotoTab(tab, url) {
|
|
135
|
+
this.requireTab(tab);
|
|
136
|
+
await this.send('Page.navigate', { url }, this.sessionId);
|
|
137
|
+
if (this.opts.settleMs > 0)
|
|
138
|
+
await sleep(this.opts.settleMs);
|
|
139
|
+
return String(await this.evalInTab(tab, 'location.href'));
|
|
140
|
+
}
|
|
141
|
+
/** innerText read, optional selector scope, capped. */
|
|
142
|
+
async readTab(tab, selector, maxChars = 6000) {
|
|
143
|
+
this.requireTab(tab);
|
|
144
|
+
const expr = `(() => { const el = ${selector ? `document.querySelector(${JSON.stringify(selector)})` : 'document.body'}; return el ? (el.innerText || '').slice(0, ${Math.max(1, maxChars)}) : ''; })()`;
|
|
145
|
+
return String((await this.evalInTab(tab, expr)) ?? '');
|
|
146
|
+
}
|
|
147
|
+
/** Runtime.evaluate in the agent tab (optional backend capability used by extract/evaluate). */
|
|
148
|
+
async evalInTab(tab, expression, timeoutMs) {
|
|
149
|
+
this.requireTab(tab);
|
|
150
|
+
const res = (await this.send('Runtime.evaluate', { expression, returnByValue: true, awaitPromise: true }, this.sessionId, timeoutMs ?? 30_000));
|
|
151
|
+
if (res.exceptionDetails) {
|
|
152
|
+
throw new AttachError('UNKNOWN', `page evaluation failed: ${res.exceptionDetails.text ?? 'exception'}`);
|
|
153
|
+
}
|
|
154
|
+
const value = res.result?.value;
|
|
155
|
+
if (typeof value === 'string' && value.length > this.opts.evalMaxChars) {
|
|
156
|
+
throw new AttachError('UNKNOWN', `eval result exceeds ${this.opts.evalMaxChars} chars`);
|
|
157
|
+
}
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
requireTab(tab) {
|
|
161
|
+
if (!this.sessionId || tab !== this.createdTargetId) {
|
|
162
|
+
throw new AttachError('TAB_CLOSED', 'agent tab is not claimed on this transport');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
onMessage(data) {
|
|
166
|
+
let m;
|
|
167
|
+
try {
|
|
168
|
+
m = JSON.parse(data);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (!m.id || !this.pending.has(m.id))
|
|
174
|
+
return;
|
|
175
|
+
const p = this.pending.get(m.id);
|
|
176
|
+
this.pending.delete(m.id);
|
|
177
|
+
clearTimeout(p.timer);
|
|
178
|
+
if (m.error)
|
|
179
|
+
p.reject(new AttachError('UNKNOWN', m.error.message));
|
|
180
|
+
else
|
|
181
|
+
p.resolve(m.result);
|
|
182
|
+
}
|
|
183
|
+
failAllPending(reason) {
|
|
184
|
+
const err = new AttachError('CDP_UNAVAILABLE', reason);
|
|
185
|
+
for (const [, p] of this.pending) {
|
|
186
|
+
clearTimeout(p.timer);
|
|
187
|
+
p.reject(err);
|
|
188
|
+
}
|
|
189
|
+
this.pending.clear();
|
|
190
|
+
if (this.ws) {
|
|
191
|
+
this.ws = null;
|
|
192
|
+
this.sessionId = null;
|
|
193
|
+
this.onUnexpectedClose?.(err);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
send(method, params = {}, sessionId, timeoutMs) {
|
|
197
|
+
const ws = this.ws;
|
|
198
|
+
if (!ws)
|
|
199
|
+
return Promise.reject(new AttachError('CDP_UNAVAILABLE', 'transport is not connected'));
|
|
200
|
+
const id = ++this.nextId;
|
|
201
|
+
const deadline = timeoutMs ?? this.opts.commandTimeoutMs;
|
|
202
|
+
return new Promise((resolve, reject) => {
|
|
203
|
+
const timer = setTimeout(() => {
|
|
204
|
+
if (this.pending.delete(id)) {
|
|
205
|
+
reject(new AttachError('CDP_TIMEOUT', `${method} timed out after ${deadline}ms`));
|
|
206
|
+
}
|
|
207
|
+
}, deadline);
|
|
208
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
209
|
+
ws.send(JSON.stringify(sessionId ? { id, method, params, sessionId } : { id, method, params }));
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=raw-cdp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"raw-cdp.js","sourceRoot":"","sources":["../../../src/attach/backends/raw-cdp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type DaemonStatusFile } from './protocol.js';
|
|
2
|
+
/** Client options. */
|
|
3
|
+
export interface AttachDaemonClientOptions {
|
|
4
|
+
ipcDir?: string;
|
|
5
|
+
/** Client name prefix used in ids and claimant identity (default `client`). */
|
|
6
|
+
client?: string;
|
|
7
|
+
/** Response poll cadence ms (default 400). */
|
|
8
|
+
pollMs?: number;
|
|
9
|
+
/** Base per-op timeout ms before per-op margins (default 45000). */
|
|
10
|
+
opTimeoutMs?: number;
|
|
11
|
+
}
|
|
12
|
+
/** See fileoverview. All failures throw {@link AttachError} with a structured code. */
|
|
13
|
+
export declare class AttachDaemonClient {
|
|
14
|
+
readonly ipcDir: string;
|
|
15
|
+
readonly client: string;
|
|
16
|
+
private readonly pollMs;
|
|
17
|
+
private readonly opTimeoutMs;
|
|
18
|
+
constructor(opts?: AttachDaemonClientOptions);
|
|
19
|
+
/** Fast, round-trip-free snapshot of status.json (undefined when absent). */
|
|
20
|
+
statusFile(): DaemonStatusFile | undefined;
|
|
21
|
+
/** True when status.json shows a fresh heartbeat or a live recorded pid. */
|
|
22
|
+
daemonLooksAlive(): boolean;
|
|
23
|
+
/** Liveness echo through the queue. */
|
|
24
|
+
ping(): Promise<{
|
|
25
|
+
pong: boolean;
|
|
26
|
+
pid: number;
|
|
27
|
+
}>;
|
|
28
|
+
/** Controller + daemon status snapshot via the queue. */
|
|
29
|
+
status(): Promise<Record<string, unknown>>;
|
|
30
|
+
/** Acquire driving rights (and trigger the controller claim on first use). */
|
|
31
|
+
claim(ttlMs?: number): Promise<Record<string, unknown>>;
|
|
32
|
+
/** Navigate the agent tab (daemon settles for `settle` ms, default 1800). */
|
|
33
|
+
goto(url: string, o?: {
|
|
34
|
+
settle?: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
url: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Read visible text (untrusted page content). */
|
|
39
|
+
read(o?: {
|
|
40
|
+
selector?: string;
|
|
41
|
+
maxChars?: number;
|
|
42
|
+
}): Promise<{
|
|
43
|
+
untrusted: true;
|
|
44
|
+
text: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Structured extraction via a selector map (untrusted page content). */
|
|
47
|
+
extract(fields?: Record<string, string>): Promise<{
|
|
48
|
+
untrusted: true;
|
|
49
|
+
data: unknown;
|
|
50
|
+
}>;
|
|
51
|
+
/** USER LANE ONLY: arbitrary page evaluation for user-authored scripts. */
|
|
52
|
+
evaluate(expression: string, timeoutMs?: number): Promise<{
|
|
53
|
+
untrusted: true;
|
|
54
|
+
value: unknown;
|
|
55
|
+
}>;
|
|
56
|
+
/** Give up driving rights (daemon parks the tab; its session persists). */
|
|
57
|
+
release(): Promise<void>;
|
|
58
|
+
/** Runtime session controls. */
|
|
59
|
+
control(action: 'pause' | 'resume' | 'dry_run_on' | 'dry_run_off' | 'status'): Promise<Record<string, unknown>>;
|
|
60
|
+
/** Full daemon shutdown (parks tab, releases lease; Chrome untouched). */
|
|
61
|
+
quit(): Promise<void>;
|
|
62
|
+
private request;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/attach/daemon/client.ts"],"names":[],"mappings":"AAgBA,OAAO,EAWL,KAAK,gBAAgB,EACtB,MAAM,eAAe,CAAC;AAEvB,sBAAsB;AACtB,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID,uFAAuF;AACvF,qBAAa,kBAAkB;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;gBAEzB,IAAI,GAAE,yBAA8B;IAOhD,6EAA6E;IAC7E,UAAU,IAAI,gBAAgB,GAAG,SAAS;IAI1C,4EAA4E;IAC5E,gBAAgB,IAAI,OAAO;IAY3B,uCAAuC;IACjC,IAAI,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAIrD,yDAAyD;IACnD,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIhD,8EAA8E;IACxE,KAAK,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAI7D,6EAA6E;IACvE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAI9E,kDAAkD;IAC5C,IAAI,CAAC,CAAC,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAIxG,yEAAyE;IACnE,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAI3F,2EAA2E;IACrE,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,SAAS,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAOpG,2EAA2E;IACrE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAI9B,gCAAgC;IAC1B,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,YAAY,GAAG,aAAa,GAAG,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAIrH,0EAA0E;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAIb,OAAO;CA6BtB"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Typed client for the attach daemon's file queue.
|
|
3
|
+
*
|
|
4
|
+
* No network, no child processes: writes `cmd-<id>.json`, polls for
|
|
5
|
+
* `resp-<id>.json`, deletes the response after reading. Used by user scripts
|
|
6
|
+
* (`wunderland attach run`), the declarative runner, and the tools'
|
|
7
|
+
* DaemonAttachSurface. `evaluate` is the user lane; no agent tool reaches it.
|
|
8
|
+
*
|
|
9
|
+
* Liveness: a daemon mid-op can miss heartbeats (the loop is serial), so
|
|
10
|
+
* {@link AttachDaemonClient.daemonLooksAlive} accepts a fresh heartbeat OR a
|
|
11
|
+
* live recorded pid.
|
|
12
|
+
*
|
|
13
|
+
* @module browser-automation/attach/daemon/client
|
|
14
|
+
*/
|
|
15
|
+
import { unlinkSync, existsSync } from 'node:fs';
|
|
16
|
+
import { AttachError } from '../errors.js';
|
|
17
|
+
import { resolveIpcDir, newCmdId, writeAtomicJson, readJson, cmdPath, respPath, statusPath, HEARTBEAT_STALE_MS, } from './protocol.js';
|
|
18
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
19
|
+
/** See fileoverview. All failures throw {@link AttachError} with a structured code. */
|
|
20
|
+
export class AttachDaemonClient {
|
|
21
|
+
ipcDir;
|
|
22
|
+
client;
|
|
23
|
+
pollMs;
|
|
24
|
+
opTimeoutMs;
|
|
25
|
+
constructor(opts = {}) {
|
|
26
|
+
this.ipcDir = resolveIpcDir(opts.ipcDir);
|
|
27
|
+
this.client = `${opts.client ?? 'client'}-${process.pid}`;
|
|
28
|
+
this.pollMs = opts.pollMs ?? 400;
|
|
29
|
+
this.opTimeoutMs = opts.opTimeoutMs ?? 45_000;
|
|
30
|
+
}
|
|
31
|
+
/** Fast, round-trip-free snapshot of status.json (undefined when absent). */
|
|
32
|
+
statusFile() {
|
|
33
|
+
return readJson(statusPath(this.ipcDir));
|
|
34
|
+
}
|
|
35
|
+
/** True when status.json shows a fresh heartbeat or a live recorded pid. */
|
|
36
|
+
daemonLooksAlive() {
|
|
37
|
+
const s = this.statusFile();
|
|
38
|
+
if (!s || s.state === 'stopped' || s.state === 'failed')
|
|
39
|
+
return false;
|
|
40
|
+
if (Date.now() - s.t <= HEARTBEAT_STALE_MS)
|
|
41
|
+
return true;
|
|
42
|
+
try {
|
|
43
|
+
process.kill(s.pid, 0);
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Liveness echo through the queue. */
|
|
51
|
+
async ping() {
|
|
52
|
+
return (await this.request('ping'));
|
|
53
|
+
}
|
|
54
|
+
/** Controller + daemon status snapshot via the queue. */
|
|
55
|
+
async status() {
|
|
56
|
+
return (await this.request('status'));
|
|
57
|
+
}
|
|
58
|
+
/** Acquire driving rights (and trigger the controller claim on first use). */
|
|
59
|
+
async claim(ttlMs) {
|
|
60
|
+
return (await this.request('claim', ttlMs ? { ttlMs } : {}));
|
|
61
|
+
}
|
|
62
|
+
/** Navigate the agent tab (daemon settles for `settle` ms, default 1800). */
|
|
63
|
+
async goto(url, o = {}) {
|
|
64
|
+
return (await this.request('goto', { url, ...o }, this.opTimeoutMs + (o.settle ?? 1800)));
|
|
65
|
+
}
|
|
66
|
+
/** Read visible text (untrusted page content). */
|
|
67
|
+
async read(o = {}) {
|
|
68
|
+
return (await this.request('read', o));
|
|
69
|
+
}
|
|
70
|
+
/** Structured extraction via a selector map (untrusted page content). */
|
|
71
|
+
async extract(fields) {
|
|
72
|
+
return (await this.request('extract', fields ? { fields } : {}));
|
|
73
|
+
}
|
|
74
|
+
/** USER LANE ONLY: arbitrary page evaluation for user-authored scripts. */
|
|
75
|
+
async evaluate(expression, timeoutMs) {
|
|
76
|
+
return (await this.request('eval', { expression, timeoutMs }, this.opTimeoutMs + (timeoutMs ?? 30_000)));
|
|
77
|
+
}
|
|
78
|
+
/** Give up driving rights (daemon parks the tab; its session persists). */
|
|
79
|
+
async release() {
|
|
80
|
+
await this.request('release');
|
|
81
|
+
}
|
|
82
|
+
/** Runtime session controls. */
|
|
83
|
+
async control(action) {
|
|
84
|
+
return (await this.request('control', { action }));
|
|
85
|
+
}
|
|
86
|
+
/** Full daemon shutdown (parks tab, releases lease; Chrome untouched). */
|
|
87
|
+
async quit() {
|
|
88
|
+
await this.request('quit');
|
|
89
|
+
}
|
|
90
|
+
async request(op, args = {}, timeoutMs) {
|
|
91
|
+
if (!this.daemonLooksAlive()) {
|
|
92
|
+
throw new AttachError('DAEMON_UNAVAILABLE', 'no live attach daemon behind this IPC dir; run `wunderland attach start`');
|
|
93
|
+
}
|
|
94
|
+
const id = newCmdId(this.client);
|
|
95
|
+
const cmdFile = cmdPath(this.ipcDir, id);
|
|
96
|
+
const respFile = respPath(this.ipcDir, id);
|
|
97
|
+
writeAtomicJson(cmdFile, { id, client: this.client, op, args });
|
|
98
|
+
const deadline = Date.now() + (timeoutMs ?? this.opTimeoutMs);
|
|
99
|
+
while (Date.now() < deadline) {
|
|
100
|
+
await sleep(this.pollMs);
|
|
101
|
+
const resp = readJson(respFile);
|
|
102
|
+
if (!resp)
|
|
103
|
+
continue;
|
|
104
|
+
try {
|
|
105
|
+
unlinkSync(respFile);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
/* raced with GC */
|
|
109
|
+
}
|
|
110
|
+
if (resp.ok)
|
|
111
|
+
return resp.data;
|
|
112
|
+
throw new AttachError(resp.error.code, resp.error.message);
|
|
113
|
+
}
|
|
114
|
+
const consumed = !existsSync(cmdFile);
|
|
115
|
+
throw new AttachError(consumed ? 'CDP_TIMEOUT' : 'DAEMON_UNAVAILABLE', consumed
|
|
116
|
+
? `${op} timed out awaiting the daemon's response`
|
|
117
|
+
: `${op} was never consumed — daemon gone; run \`wunderland attach start\``);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/attach/daemon/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** A held daemon lock. */
|
|
2
|
+
export interface DaemonLock {
|
|
3
|
+
/** Absolute pidfile path backing the lock. */
|
|
4
|
+
readonly pidFile: string;
|
|
5
|
+
/** Remove the pidfile iff this process still owns it. Never throws. */
|
|
6
|
+
release(): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Acquire the daemon singleton atomically.
|
|
10
|
+
*
|
|
11
|
+
* Creates `pidFile` with the `wx` flag (fails when it exists). On EEXIST the
|
|
12
|
+
* holder is inspected: a live pid refuses acquisition with `DAEMON_RUNNING`;
|
|
13
|
+
* a dead pid or an unreadable body reclaims the file once. Concurrent
|
|
14
|
+
* acquirers race safely on the atomic create — exactly one wins.
|
|
15
|
+
*
|
|
16
|
+
* @throws {AttachError} `DAEMON_RUNNING` when another live daemon holds the lock.
|
|
17
|
+
*/
|
|
18
|
+
export declare function acquireDaemonLock(pidFile: string): DaemonLock;
|
|
19
|
+
//# sourceMappingURL=daemon-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-lock.d.ts","sourceRoot":"","sources":["../../../src/attach/daemon/daemon-lock.ts"],"names":[],"mappings":"AAmBA,0BAA0B;AAC1B,MAAM,WAAW,UAAU;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uEAAuE;IACvE,OAAO,IAAI,IAAI,CAAC;CACjB;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAsC7D"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Atomic daemon singleton via an O_EXCL pidfile.
|
|
3
|
+
*
|
|
4
|
+
* Mutual exclusion for the attach daemon: exactly one daemon may hold one
|
|
5
|
+
* Chrome session, or concurrent `attach start`s would open two CDP sockets
|
|
6
|
+
* and raise two macOS Local Network prompts. NOTE: `../singleton-lock.ts` is,
|
|
7
|
+
* despite its name, a parser for Chrome's own SingletonLock symlink (JXA pid
|
|
8
|
+
* addressing) and provides no locking — this module is the daemon's lock.
|
|
9
|
+
*
|
|
10
|
+
* Reclaim policy is pid-liveness, not age: a lock whose recorded pid is dead
|
|
11
|
+
* (or whose body is unreadable/torn) is reclaimed; a live pid refuses the
|
|
12
|
+
* acquisition no matter how old the file is.
|
|
13
|
+
*
|
|
14
|
+
* @module browser-automation/attach/daemon/daemon-lock
|
|
15
|
+
*/
|
|
16
|
+
import { openSync, writeSync, closeSync, readFileSync, unlinkSync, mkdirSync } from 'node:fs';
|
|
17
|
+
import { dirname } from 'node:path';
|
|
18
|
+
import { AttachError } from '../errors.js';
|
|
19
|
+
/** True when `pid` refers to a live process we may signal (EPERM counts as alive). */
|
|
20
|
+
function pidAlive(pid) {
|
|
21
|
+
try {
|
|
22
|
+
process.kill(pid, 0);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
return err.code === 'EPERM';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Acquire the daemon singleton atomically.
|
|
31
|
+
*
|
|
32
|
+
* Creates `pidFile` with the `wx` flag (fails when it exists). On EEXIST the
|
|
33
|
+
* holder is inspected: a live pid refuses acquisition with `DAEMON_RUNNING`;
|
|
34
|
+
* a dead pid or an unreadable body reclaims the file once. Concurrent
|
|
35
|
+
* acquirers race safely on the atomic create — exactly one wins.
|
|
36
|
+
*
|
|
37
|
+
* @throws {AttachError} `DAEMON_RUNNING` when another live daemon holds the lock.
|
|
38
|
+
*/
|
|
39
|
+
export function acquireDaemonLock(pidFile) {
|
|
40
|
+
mkdirSync(dirname(pidFile), { recursive: true, mode: 0o700 });
|
|
41
|
+
const body = { pid: process.pid, startedAt: Date.now() };
|
|
42
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
43
|
+
try {
|
|
44
|
+
const fd = openSync(pidFile, 'wx', 0o600);
|
|
45
|
+
writeSync(fd, JSON.stringify(body));
|
|
46
|
+
closeSync(fd);
|
|
47
|
+
return {
|
|
48
|
+
pidFile,
|
|
49
|
+
release() {
|
|
50
|
+
try {
|
|
51
|
+
const cur = JSON.parse(readFileSync(pidFile, 'utf8'));
|
|
52
|
+
if (cur.pid === process.pid)
|
|
53
|
+
unlinkSync(pidFile);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* released best-effort: file gone or owned by a newer daemon */
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (err.code !== 'EEXIST')
|
|
63
|
+
throw err;
|
|
64
|
+
let holder;
|
|
65
|
+
try {
|
|
66
|
+
holder = JSON.parse(readFileSync(pidFile, 'utf8'));
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
/* torn or unreadable body: treat as reclaimable */
|
|
70
|
+
}
|
|
71
|
+
if (holder && pidAlive(holder.pid)) {
|
|
72
|
+
throw new AttachError('DAEMON_RUNNING', `daemon already running (pid ${holder.pid})`);
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
unlinkSync(pidFile);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
/* raced with another reclaimer; the retry create decides the winner */
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
throw new AttachError('DAEMON_RUNNING', 'daemon lock contention: another process reclaimed the pidfile first');
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=daemon-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-lock.js","sourceRoot":"","sources":["../../../src/attach/daemon/daemon-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9F,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAgB3C,sFAAsF;AACtF,SAAS,QAAQ,CAAC,GAAW;IAC3B,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAQ,GAA6B,CAAC,IAAI,KAAK,OAAO,CAAC;IACzD,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAa,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACnE,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC;YACH,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1C,SAAS,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YACpC,SAAS,CAAC,EAAE,CAAC,CAAC;YACd,OAAO;gBACL,OAAO;gBACP,OAAO;oBACL,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAa,CAAC;wBAClE,IAAI,GAAG,CAAC,GAAG,KAAK,OAAO,CAAC,GAAG;4BAAE,UAAU,CAAC,OAAO,CAAC,CAAC;oBACnD,CAAC;oBAAC,MAAM,CAAC;wBACP,gEAAgE;oBAClE,CAAC;gBACH,CAAC;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,GAAG,CAAC;YAChE,IAAI,MAA4B,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAa,CAAC;YACjE,CAAC;YAAC,MAAM,CAAC;gBACP,mDAAmD;YACrD,CAAC;YACD,IAAI,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBACnC,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,+BAA+B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC;YACxF,CAAC;YACD,IAAI,CAAC;gBACH,UAAU,CAAC,OAAO,CAAC,CAAC;YACtB,CAAC;YAAC,MAAM,CAAC;gBACP,uEAAuE;YACzE,CAAC;QACH,CAAC;IACH,CAAC;IACD,MAAM,IAAI,WAAW,CAAC,gBAAgB,EAAE,qEAAqE,CAAC,CAAC;AACjH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build and run the daemon from an environment map. Returns the process exit
|
|
3
|
+
* code (0 clean stop, 2 failure). Exported for tests and for the CLI.
|
|
4
|
+
*/
|
|
5
|
+
export declare function main(env?: Record<string, string | undefined>): Promise<number>;
|
|
6
|
+
/**
|
|
7
|
+
* True when `moduleUrl` is the script Node was started with (`node <entryPath>`).
|
|
8
|
+
*
|
|
9
|
+
* Both sides resolve to a real path before the comparison: a file URL
|
|
10
|
+
* percent-encodes characters such as spaces, Node follows symlinks when it
|
|
11
|
+
* builds `import.meta.url` for the entry script but keeps them under
|
|
12
|
+
* `--preserve-symlinks-main`, and the entry path may be relative. A missing
|
|
13
|
+
* or unreadable entry path, or a module URL that is not a file, is not this
|
|
14
|
+
* module. Exported for tests.
|
|
15
|
+
*/
|
|
16
|
+
export declare function isEntryPoint(moduleUrl: string, entryPath: string | undefined): boolean;
|
|
17
|
+
//# sourceMappingURL=daemon-main.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-main.d.ts","sourceRoot":"","sources":["../../../src/attach/daemon/daemon-main.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,wBAAsB,IAAI,CAAC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDjG;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAOtF"}
|