@framers/agentos-ext-browser-automation 0.2.0 → 0.3.0
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 +91 -0
- package/dist/BrowserService.js +9 -45
- package/dist/BrowserService.js.map +1 -1
- package/dist/attach/AttachController.d.ts +54 -0
- package/dist/attach/AttachController.d.ts.map +1 -1
- package/dist/attach/AttachController.js +129 -41
- package/dist/attach/AttachController.js.map +1 -1
- package/dist/attach/backends/jxa.d.ts.map +1 -1
- package/dist/attach/backends/jxa.js +35 -62
- package/dist/attach/backends/jxa.js.map +1 -1
- package/dist/attach/backends/raw-cdp.d.ts +14 -0
- package/dist/attach/backends/raw-cdp.d.ts.map +1 -1
- package/dist/attach/backends/raw-cdp.js +66 -35
- package/dist/attach/backends/raw-cdp.js.map +1 -1
- package/dist/attach/daemon/client.d.ts +10 -0
- package/dist/attach/daemon/client.d.ts.map +1 -1
- package/dist/attach/daemon/client.js +34 -23
- package/dist/attach/daemon/client.js.map +1 -1
- package/dist/attach/daemon/daemon-lock.js +14 -17
- package/dist/attach/daemon/daemon-lock.js.map +1 -1
- package/dist/attach/daemon/daemon-main.d.ts +11 -0
- package/dist/attach/daemon/daemon-main.d.ts.map +1 -1
- package/dist/attach/daemon/daemon-main.js +39 -18
- package/dist/attach/daemon/daemon-main.js.map +1 -1
- package/dist/attach/daemon/daemon.d.ts.map +1 -1
- package/dist/attach/daemon/daemon.js +49 -32
- package/dist/attach/daemon/daemon.js.map +1 -1
- package/dist/attach/daemon/index.js +7 -25
- package/dist/attach/daemon/index.js.map +1 -1
- package/dist/attach/daemon/protocol.d.ts +1 -1
- package/dist/attach/daemon/protocol.d.ts.map +1 -1
- package/dist/attach/daemon/protocol.js +33 -45
- package/dist/attach/daemon/protocol.js.map +1 -1
- package/dist/attach/daemon/runner.js +1 -4
- package/dist/attach/daemon/runner.js.map +1 -1
- package/dist/attach/daemon/surface.d.ts +5 -0
- package/dist/attach/daemon/surface.d.ts.map +1 -1
- package/dist/attach/daemon/surface.js +16 -14
- package/dist/attach/daemon/surface.js.map +1 -1
- package/dist/attach/devtools-port.js +1 -4
- package/dist/attach/devtools-port.js.map +1 -1
- package/dist/attach/errors.js +4 -9
- package/dist/attach/errors.js.map +1 -1
- package/dist/attach/evidence.d.ts +64 -0
- package/dist/attach/evidence.d.ts.map +1 -0
- package/dist/attach/evidence.js +269 -0
- package/dist/attach/evidence.js.map +1 -0
- package/dist/attach/lease.js +18 -23
- package/dist/attach/lease.js.map +1 -1
- package/dist/attach/singleton-lock.js +1 -4
- package/dist/attach/singleton-lock.js.map +1 -1
- package/dist/attach/state.js +6 -13
- package/dist/attach/state.js.map +1 -1
- package/dist/attach/tools.d.ts +42 -2
- package/dist/attach/tools.d.ts.map +1 -1
- package/dist/attach/tools.js +124 -88
- package/dist/attach/tools.js.map +1 -1
- package/dist/attach/url-policy.js +2 -6
- package/dist/attach/url-policy.js.map +1 -1
- package/dist/attach.js +7 -23
- package/dist/attach.js.map +1 -1
- 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 +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -75
- 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 +5 -4
- package/dist/attach/__tests__/AttachController.test.d.ts +0 -2
- package/dist/attach/__tests__/AttachController.test.d.ts.map +0 -1
- package/dist/attach/__tests__/AttachController.test.js +0 -278
- package/dist/attach/__tests__/AttachController.test.js.map +0 -1
- package/dist/attach/__tests__/attach-primitives.test.d.ts +0 -2
- package/dist/attach/__tests__/attach-primitives.test.d.ts.map +0 -1
- package/dist/attach/__tests__/attach-primitives.test.js +0 -158
- package/dist/attach/__tests__/attach-primitives.test.js.map +0 -1
- package/dist/attach/__tests__/jxa-args.test.d.ts +0 -2
- package/dist/attach/__tests__/jxa-args.test.d.ts.map +0 -1
- package/dist/attach/__tests__/jxa-args.test.js +0 -37
- package/dist/attach/__tests__/jxa-args.test.js.map +0 -1
- package/dist/attach/__tests__/pack-registration.test.d.ts +0 -2
- package/dist/attach/__tests__/pack-registration.test.d.ts.map +0 -1
- package/dist/attach/__tests__/pack-registration.test.js +0 -34
- package/dist/attach/__tests__/pack-registration.test.js.map +0 -1
- package/dist/attach/__tests__/tools.test.d.ts +0 -2
- package/dist/attach/__tests__/tools.test.d.ts.map +0 -1
- package/dist/attach/__tests__/tools.test.js +0 -155
- package/dist/attach/__tests__/tools.test.js.map +0 -1
- package/dist/attach/backends/__tests__/raw-cdp.test.d.ts +0 -2
- package/dist/attach/backends/__tests__/raw-cdp.test.d.ts.map +0 -1
- package/dist/attach/backends/__tests__/raw-cdp.test.js +0 -133
- package/dist/attach/backends/__tests__/raw-cdp.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/client.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/client.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/client.test.js +0 -58
- package/dist/attach/daemon/__tests__/client.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-lock.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/daemon-lock.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-lock.test.js +0 -72
- package/dist/attach/daemon/__tests__/daemon-lock.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.js +0 -102
- package/dist/attach/daemon/__tests__/daemon-loop.integration.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/harness.d.ts +0 -44
- package/dist/attach/daemon/__tests__/harness.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/harness.js +0 -96
- package/dist/attach/daemon/__tests__/harness.js.map +0 -1
- package/dist/attach/daemon/__tests__/protocol.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/protocol.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/protocol.test.js +0 -71
- package/dist/attach/daemon/__tests__/protocol.test.js.map +0 -1
- package/dist/attach/daemon/__tests__/runner.test.d.ts +0 -2
- package/dist/attach/daemon/__tests__/runner.test.d.ts.map +0 -1
- package/dist/attach/daemon/__tests__/runner.test.js +0 -67
- package/dist/attach/daemon/__tests__/runner.test.js.map +0 -1
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Where an attach session's screenshots are written: one
|
|
3
|
+
* evidence directory, and the checks that keep a write inside it.
|
|
4
|
+
*
|
|
5
|
+
* A screenshot's path comes from a tool argument, so it must not reach the
|
|
6
|
+
* rest of the disk or replace a file. It is read against the evidence
|
|
7
|
+
* directory, refused when it leaves it or passes through a link, and written
|
|
8
|
+
* to a new file only.
|
|
9
|
+
*
|
|
10
|
+
* The directory is private to this user, by the rules the media packs keep
|
|
11
|
+
* for the files they save (`imageFiles.ts`, `audioFiles.ts`). The evidence
|
|
12
|
+
* directory and each directory in it on the way to the file belong to this
|
|
13
|
+
* user and are writable by no one else. Each directory above the evidence
|
|
14
|
+
* directory belongs to this user or root and is writable by no one else
|
|
15
|
+
* unless it is sticky, as /tmp is. A user who could rename an entry on that
|
|
16
|
+
* path could swap a directory for a link between the checks and the write,
|
|
17
|
+
* and Node has no `openat` to create a file in a checked directory. On
|
|
18
|
+
* Windows, where Node reads no ACLs, only the directories' kind is checked.
|
|
19
|
+
*
|
|
20
|
+
* A page takes seconds to capture, so the directories are checked twice:
|
|
21
|
+
* before the capture, so that nothing is asked of the browser for a path
|
|
22
|
+
* that will be refused, and again around the creation of the file, before
|
|
23
|
+
* the image is written through its handle.
|
|
24
|
+
*
|
|
25
|
+
* @module browser-automation/attach/evidence
|
|
26
|
+
*/
|
|
27
|
+
import { constants as fsConstants } from 'node:fs';
|
|
28
|
+
import { access, lstat, mkdir, open, realpath, unlink } from 'node:fs/promises';
|
|
29
|
+
import { homedir } from 'node:os';
|
|
30
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
31
|
+
import { AttachError } from './errors.js';
|
|
32
|
+
/** The evidence directory when none is configured. */
|
|
33
|
+
export const DEFAULT_EVIDENCE_DIR = join(homedir(), '.wunderland', 'attach-evidence');
|
|
34
|
+
const blocked = (message) => new AttachError('POLICY_BLOCKED', message);
|
|
35
|
+
/** A mode's permission bits as four octal digits. */
|
|
36
|
+
const octal = (mode) => (mode & 4095n).toString(8).padStart(4, '0');
|
|
37
|
+
/**
|
|
38
|
+
* The path inside `root` that `filePath` names when read against it, or
|
|
39
|
+
* `undefined` when it names `root` itself or a place outside it.
|
|
40
|
+
*/
|
|
41
|
+
function insideOf(root, filePath) {
|
|
42
|
+
const inside = relative(root, resolve(root, filePath));
|
|
43
|
+
return inside === '' || inside === '..' || inside.startsWith(`..${sep}`) || isAbsolute(inside) ? undefined : inside;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Refuses, by the text of the path alone, a path that names no file, and a
|
|
47
|
+
* relative path that leaves the evidence directory. A relative path reads the
|
|
48
|
+
* same against the directory however the directory is named, so it is settled
|
|
49
|
+
* here, before the disk is touched. An absolute path is settled by
|
|
50
|
+
* {@link nameInside}, once the directory's real path is known.
|
|
51
|
+
*
|
|
52
|
+
* @throws POLICY_BLOCKED
|
|
53
|
+
*/
|
|
54
|
+
function checkName(filePath, configured) {
|
|
55
|
+
if (typeof filePath !== 'string' ||
|
|
56
|
+
!filePath.trim() ||
|
|
57
|
+
filePath.includes('\0') ||
|
|
58
|
+
filePath.endsWith('/') ||
|
|
59
|
+
filePath.endsWith(sep)) {
|
|
60
|
+
throw blocked('screenshot path must name a file inside the evidence directory');
|
|
61
|
+
}
|
|
62
|
+
if (!isAbsolute(filePath) && insideOf(configured, filePath) === undefined) {
|
|
63
|
+
throw blocked(`screenshot path must stay inside the evidence directory (${configured})`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The path inside the evidence directory that `filePath` names. An absolute
|
|
68
|
+
* path may name the directory by its real path (`root`), as a result of
|
|
69
|
+
* {@link prepareEvidenceFile} does, or as it is configured.
|
|
70
|
+
*
|
|
71
|
+
* @throws POLICY_BLOCKED when the path is outside the directory.
|
|
72
|
+
*/
|
|
73
|
+
function nameInside(filePath, configured, root) {
|
|
74
|
+
const inside = insideOf(root, filePath) ?? insideOf(configured, filePath);
|
|
75
|
+
if (inside === undefined) {
|
|
76
|
+
throw blocked(`screenshot path must stay inside the evidence directory (${root})`);
|
|
77
|
+
}
|
|
78
|
+
return inside;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* `dir` as a directory private to this user: a directory, not a link, that
|
|
82
|
+
* this user owns and that neither its group nor others can write. Where the
|
|
83
|
+
* platform has no user ids (Windows) only the kind is checked.
|
|
84
|
+
*
|
|
85
|
+
* @throws POLICY_BLOCKED when it is anything else.
|
|
86
|
+
*/
|
|
87
|
+
async function privateDirectory(dir) {
|
|
88
|
+
const stat = await lstat(dir, { bigint: true });
|
|
89
|
+
if (!stat.isDirectory()) {
|
|
90
|
+
throw blocked(`screenshot path passes through ${dir}, which is not a directory (a link is refused)`);
|
|
91
|
+
}
|
|
92
|
+
if (typeof process.getuid === 'function' && (stat.uid !== BigInt(process.getuid()) || (stat.mode & 18n) !== 0n)) {
|
|
93
|
+
throw blocked(`${dir} must belong to this user and be writable by no one else (owner uid ${stat.uid}, mode ${octal(stat.mode)}): chmod 700 it, or set another evidence directory`);
|
|
94
|
+
}
|
|
95
|
+
return { path: dir, dev: stat.dev, ino: stat.ino };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Why another user could change a directory above `dir`, a real path, or
|
|
99
|
+
* `undefined` when none can: each directory above it must belong to this
|
|
100
|
+
* user or root and be writable by no one else, unless it is sticky, where
|
|
101
|
+
* only an entry's owner can rename it. Where the platform has no user ids
|
|
102
|
+
* (Windows) nothing is checked.
|
|
103
|
+
*/
|
|
104
|
+
async function changeableParent(dir) {
|
|
105
|
+
if (typeof process.getuid !== 'function')
|
|
106
|
+
return undefined;
|
|
107
|
+
const uid = BigInt(process.getuid());
|
|
108
|
+
for (let parent = dirname(dir);; parent = dirname(parent)) {
|
|
109
|
+
const stat = await lstat(parent, { bigint: true });
|
|
110
|
+
if (!stat.isDirectory())
|
|
111
|
+
return `${parent}, above it, is not a directory`;
|
|
112
|
+
if (stat.uid !== uid && stat.uid !== 0n) {
|
|
113
|
+
return `${parent}, above it, belongs to uid ${stat.uid} (mode ${octal(stat.mode)})`;
|
|
114
|
+
}
|
|
115
|
+
if ((stat.mode & 18n) !== 0n && (stat.mode & 512n) === 0n) {
|
|
116
|
+
return `${parent}, above it, can be written by others and is not sticky (owner uid ${stat.uid}, mode ${octal(stat.mode)})`;
|
|
117
|
+
}
|
|
118
|
+
if (dirname(parent) === parent)
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Whether each checked directory is still that directory: the same device and inode, and not a link. */
|
|
123
|
+
async function unchanged(directories) {
|
|
124
|
+
for (const checked of directories) {
|
|
125
|
+
const now = await lstat(checked.path, { bigint: true }).catch(() => undefined);
|
|
126
|
+
if (!now?.isDirectory() || now.dev !== checked.dev || now.ino !== checked.ino)
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The path a screenshot at `filePath` would be written to, for a dry run:
|
|
133
|
+
* the same reading of the path as {@link prepareEvidenceFile}, with nothing
|
|
134
|
+
* made on the disk. The evidence directory is named by its real path when it
|
|
135
|
+
* exists, as a written screenshot's path is.
|
|
136
|
+
*
|
|
137
|
+
* @param evidenceDir - The configured evidence directory, or `undefined` for the default.
|
|
138
|
+
* @param filePath - The path asked for, relative to the directory or absolute inside it.
|
|
139
|
+
* @throws POLICY_BLOCKED when the path names no file or leaves the directory.
|
|
140
|
+
*/
|
|
141
|
+
export async function plannedEvidencePath(evidenceDir, filePath) {
|
|
142
|
+
const configured = resolve(evidenceDir ?? DEFAULT_EVIDENCE_DIR);
|
|
143
|
+
checkName(filePath, configured);
|
|
144
|
+
const root = await realpath(configured).catch(() => configured);
|
|
145
|
+
return join(root, nameInside(filePath, configured, root));
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Prepares the file a screenshot is written to, before the page is captured.
|
|
149
|
+
* The evidence directory is made when missing (mode 0700) and read by its
|
|
150
|
+
* real path, so a link swapped in for it later moves nothing. Each directory
|
|
151
|
+
* from it to the file is made (mode 0700) or checked: a directory, not a
|
|
152
|
+
* link, private to this user, with no directory above the evidence directory
|
|
153
|
+
* that another user can change. A file already at the path is refused.
|
|
154
|
+
*
|
|
155
|
+
* @param evidenceDir - The configured evidence directory, or `undefined` for the default.
|
|
156
|
+
* @param filePath - The path asked for, relative to the directory or absolute inside it.
|
|
157
|
+
* @throws POLICY_BLOCKED for a path that names no file, leaves the directory,
|
|
158
|
+
* passes through a link or a file, or names something that exists, and for
|
|
159
|
+
* a directory that is not private to this user.
|
|
160
|
+
* @throws UNKNOWN when the directory cannot take a new file (its mode, or a
|
|
161
|
+
* file system mounted read-only).
|
|
162
|
+
*/
|
|
163
|
+
export async function prepareEvidenceFile(evidenceDir, filePath) {
|
|
164
|
+
const configured = resolve(evidenceDir ?? DEFAULT_EVIDENCE_DIR);
|
|
165
|
+
checkName(filePath, configured);
|
|
166
|
+
await mkdir(configured, { recursive: true, mode: 0o700 });
|
|
167
|
+
const root = await realpath(configured);
|
|
168
|
+
const target = join(root, nameInside(filePath, configured, root));
|
|
169
|
+
const directories = [await privateDirectory(root)];
|
|
170
|
+
const changeable = await changeableParent(root);
|
|
171
|
+
if (changeable) {
|
|
172
|
+
throw blocked(`the evidence directory ${root} cannot be used: ${changeable}. Set one under directories that no other user can change`);
|
|
173
|
+
}
|
|
174
|
+
let dir = root;
|
|
175
|
+
for (const part of relative(root, dirname(target)).split(sep).filter(Boolean)) {
|
|
176
|
+
dir = join(dir, part);
|
|
177
|
+
await mkdir(dir, { mode: 0o700 }).catch((err) => {
|
|
178
|
+
// Something is there already: the check below says whether it will do.
|
|
179
|
+
if (err.code !== 'EEXIST')
|
|
180
|
+
throw err;
|
|
181
|
+
});
|
|
182
|
+
directories.push(await privateDirectory(dir));
|
|
183
|
+
}
|
|
184
|
+
if (await lstat(target).catch(() => undefined)) {
|
|
185
|
+
throw blocked(`a file is already at ${target}: a screenshot never replaces one`);
|
|
186
|
+
}
|
|
187
|
+
// A directory this user owns can still refuse a new file: asked now, not
|
|
188
|
+
// after the page is captured.
|
|
189
|
+
await access(dir, fsConstants.W_OK | fsConstants.X_OK).catch((err) => {
|
|
190
|
+
throw new AttachError('UNKNOWN', `${dir} cannot take a new file (${err.code ?? err.message})`);
|
|
191
|
+
});
|
|
192
|
+
return { target, directories };
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Whether the opened file, by its `stat`, is the one at the prepared path,
|
|
196
|
+
* with no other name, in the directories as they were checked.
|
|
197
|
+
*/
|
|
198
|
+
async function inPlace(prepared, file) {
|
|
199
|
+
const named = await lstat(prepared.target, { bigint: true }).catch(() => undefined);
|
|
200
|
+
return (file.isFile() &&
|
|
201
|
+
named !== undefined &&
|
|
202
|
+
named.nlink === 1n &&
|
|
203
|
+
named.dev === file.dev &&
|
|
204
|
+
named.ino === file.ino &&
|
|
205
|
+
(await unchanged(prepared.directories)));
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Removes what a failed write left. The bytes go through the handle, when it
|
|
209
|
+
* is still open (after a failed close it is not). The file itself goes only
|
|
210
|
+
* when its path can still be shown to reach it: nothing is removed by path
|
|
211
|
+
* alone, since by now the path may name another file.
|
|
212
|
+
*/
|
|
213
|
+
async function discard(prepared, handle, file) {
|
|
214
|
+
await handle.truncate(0).catch(() => { });
|
|
215
|
+
if (await inPlace(prepared, file))
|
|
216
|
+
await unlink(prepared.target).catch(() => { });
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Creates the prepared file and writes `bytes` to it.
|
|
220
|
+
*
|
|
221
|
+
* The directories are checked to be the ones prepared, the file is created
|
|
222
|
+
* with flag `wx` (it never replaces a file, and a link at its name is not
|
|
223
|
+
* followed), and with the file open the directories are checked again and the
|
|
224
|
+
* file is checked to be the one at its path, with no other name. Only then
|
|
225
|
+
* are the bytes written, through the handle. Node has no `openat`, so this is
|
|
226
|
+
* the order that keeps an image out of a directory swapped in while the page
|
|
227
|
+
* was captured: a file created in the wrong place stays empty.
|
|
228
|
+
*
|
|
229
|
+
* A write that fails leaves no partial image: the file is emptied through
|
|
230
|
+
* its handle, and removed when it is still the file at its path. A close
|
|
231
|
+
* that reports the write failed is an error of the call too, and the file is
|
|
232
|
+
* removed by the same rule.
|
|
233
|
+
*
|
|
234
|
+
* @throws POLICY_BLOCKED when a file is already there or a directory changed.
|
|
235
|
+
*/
|
|
236
|
+
export async function writeEvidenceFile(prepared, bytes) {
|
|
237
|
+
const changed = () => blocked('the evidence directory changed while the page was captured; no image was written');
|
|
238
|
+
if (!(await unchanged(prepared.directories)))
|
|
239
|
+
throw changed();
|
|
240
|
+
let handle;
|
|
241
|
+
try {
|
|
242
|
+
handle = await open(prepared.target, 'wx', 0o600);
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
throw err.code === 'EEXIST'
|
|
246
|
+
? blocked(`a file is already at ${prepared.target}: a screenshot never replaces one`)
|
|
247
|
+
: err;
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const file = await handle.stat({ bigint: true });
|
|
251
|
+
if (!(await inPlace(prepared, file)))
|
|
252
|
+
throw changed();
|
|
253
|
+
try {
|
|
254
|
+
await handle.writeFile(bytes);
|
|
255
|
+
// Closed here, and its error kept: a file system may report a failed
|
|
256
|
+
// write only when the file is closed (NFS, a quota).
|
|
257
|
+
await handle.close();
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
await discard(prepared, handle, file);
|
|
261
|
+
throw err;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
// After a close above this does nothing.
|
|
266
|
+
await handle.close().catch(() => { });
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=evidence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../src/attach/evidence.ts"],"names":[],"mappings":"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"}
|
package/dist/attach/lease.js
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.acquireLease = acquireLease;
|
|
4
|
-
exports.requireLease = requireLease;
|
|
5
|
-
exports.releaseLease = releaseLease;
|
|
6
1
|
/**
|
|
7
2
|
* @fileoverview Cross-process attach lease — exactly ONE session may drive the
|
|
8
3
|
* user's browser at a time.
|
|
@@ -16,10 +11,10 @@ exports.releaseLease = releaseLease;
|
|
|
16
11
|
*
|
|
17
12
|
* @module browser-automation/attach/lease
|
|
18
13
|
*/
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
import { randomBytes } from 'node:crypto';
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { dirname } from 'node:path';
|
|
17
|
+
import { AttachError } from './errors.js';
|
|
23
18
|
const DEFAULT_TTL_MS = 10 * 60 * 1000;
|
|
24
19
|
function defaultIsPidAlive(pid) {
|
|
25
20
|
try {
|
|
@@ -32,7 +27,7 @@ function defaultIsPidAlive(pid) {
|
|
|
32
27
|
}
|
|
33
28
|
function readLease(file) {
|
|
34
29
|
try {
|
|
35
|
-
return JSON.parse(
|
|
30
|
+
return JSON.parse(readFileSync(file, 'utf8'));
|
|
36
31
|
}
|
|
37
32
|
catch {
|
|
38
33
|
return undefined;
|
|
@@ -44,34 +39,34 @@ function readLease(file) {
|
|
|
44
39
|
* @returns The acquired lease (persist the nonce; ops require it).
|
|
45
40
|
* @throws {AttachError} `LEASE_DENIED` when a live, unexpired lease exists.
|
|
46
41
|
*/
|
|
47
|
-
function acquireLease(opts) {
|
|
42
|
+
export function acquireLease(opts) {
|
|
48
43
|
const now = opts.now ?? Date.now;
|
|
49
44
|
const alive = opts.isPidAlive ?? defaultIsPidAlive;
|
|
50
|
-
const existing =
|
|
45
|
+
const existing = existsSync(opts.file) ? readLease(opts.file) : undefined;
|
|
51
46
|
if (existing) {
|
|
52
47
|
const fresh = existing.expiresAt > now();
|
|
53
48
|
if (fresh && alive(existing.pid)) {
|
|
54
|
-
throw new
|
|
49
|
+
throw new AttachError('LEASE_DENIED', `attach lease held by pid ${existing.pid} until ${new Date(existing.expiresAt).toISOString()}`);
|
|
55
50
|
}
|
|
56
51
|
}
|
|
57
52
|
const lease = {
|
|
58
53
|
pid: opts.pid ?? process.pid,
|
|
59
|
-
nonce:
|
|
54
|
+
nonce: randomBytes(16).toString('hex'),
|
|
60
55
|
acquiredAt: now(),
|
|
61
56
|
expiresAt: now() + (opts.ttlMs ?? DEFAULT_TTL_MS),
|
|
62
57
|
};
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
mkdirSync(dirname(opts.file), { recursive: true });
|
|
59
|
+
writeFileSync(opts.file, JSON.stringify(lease));
|
|
65
60
|
return lease;
|
|
66
61
|
}
|
|
67
62
|
/**
|
|
68
63
|
* Assert `nonce` matches the current lease.
|
|
69
64
|
* @throws {AttachError} `LEASE_DENIED` on missing lease or nonce mismatch.
|
|
70
65
|
*/
|
|
71
|
-
function requireLease(file, nonce) {
|
|
72
|
-
const lease =
|
|
66
|
+
export function requireLease(file, nonce) {
|
|
67
|
+
const lease = existsSync(file) ? readLease(file) : undefined;
|
|
73
68
|
if (!lease || lease.nonce !== nonce) {
|
|
74
|
-
throw new
|
|
69
|
+
throw new AttachError('LEASE_DENIED', 'operation presented a stale or unknown lease nonce');
|
|
75
70
|
}
|
|
76
71
|
return lease;
|
|
77
72
|
}
|
|
@@ -80,13 +75,13 @@ function requireLease(file, nonce) {
|
|
|
80
75
|
* missing lease is a no-op.
|
|
81
76
|
* @throws {AttachError} `LEASE_DENIED` when the nonce does not match.
|
|
82
77
|
*/
|
|
83
|
-
function releaseLease(file, nonce) {
|
|
84
|
-
const lease =
|
|
78
|
+
export function releaseLease(file, nonce) {
|
|
79
|
+
const lease = existsSync(file) ? readLease(file) : undefined;
|
|
85
80
|
if (!lease)
|
|
86
81
|
return;
|
|
87
82
|
if (lease.nonce !== nonce) {
|
|
88
|
-
throw new
|
|
83
|
+
throw new AttachError('LEASE_DENIED', 'refusing to release a lease held by another session');
|
|
89
84
|
}
|
|
90
|
-
|
|
85
|
+
unlinkSync(file);
|
|
91
86
|
}
|
|
92
87
|
//# sourceMappingURL=lease.js.map
|
package/dist/attach/lease.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lease.js","sourceRoot":"","sources":["../../src/attach/lease.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lease.js","sourceRoot":"","sources":["../../src/attach/lease.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* @fileoverview Resolve the running Chrome's PID from its `SingletonLock`.
|
|
4
3
|
*
|
|
@@ -11,8 +10,6 @@
|
|
|
11
10
|
*
|
|
12
11
|
* @module browser-automation/attach/singleton-lock
|
|
13
12
|
*/
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.pidFromSingletonLock = pidFromSingletonLock;
|
|
16
13
|
/**
|
|
17
14
|
* Extract the owning PID from a `SingletonLock` symlink target.
|
|
18
15
|
*
|
|
@@ -20,7 +17,7 @@ exports.pidFromSingletonLock = pidFromSingletonLock;
|
|
|
20
17
|
* @returns The PID (e.g. `666`).
|
|
21
18
|
* @throws {Error} When the target does not end in `-<digits>`.
|
|
22
19
|
*/
|
|
23
|
-
function pidFromSingletonLock(symlinkTarget) {
|
|
20
|
+
export function pidFromSingletonLock(symlinkTarget) {
|
|
24
21
|
const m = /-(\d+)$/.exec(String(symlinkTarget).trim());
|
|
25
22
|
if (!m) {
|
|
26
23
|
throw new Error(`SingletonLock target malformed (expected "<host>-<pid>"): "${symlinkTarget}"`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"singleton-lock.js","sourceRoot":"","sources":["../../src/attach/singleton-lock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"singleton-lock.js","sourceRoot":"","sources":["../../src/attach/singleton-lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,aAAqB;IACxD,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvD,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,8DAA8D,aAAa,GAAG,CAAC,CAAC;IAClG,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
package/dist/attach/state.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AttachStateMachine = void 0;
|
|
4
|
-
exports.withDeadline = withDeadline;
|
|
5
1
|
/**
|
|
6
2
|
* @fileoverview Attach-session state machine + operation deadlines.
|
|
7
3
|
*
|
|
@@ -13,7 +9,7 @@ exports.withDeadline = withDeadline;
|
|
|
13
9
|
*
|
|
14
10
|
* @module browser-automation/attach/state
|
|
15
11
|
*/
|
|
16
|
-
|
|
12
|
+
import { AttachError } from './errors.js';
|
|
17
13
|
const LEGAL = Object.freeze({
|
|
18
14
|
disconnected: ['connecting'],
|
|
19
15
|
connecting: ['ready', 'failed', 'disconnected'],
|
|
@@ -29,10 +25,8 @@ const LEGAL = Object.freeze({
|
|
|
29
25
|
* `reading`, a failure lands in `failed` and the ONLY way forward is an
|
|
30
26
|
* explicit `disconnected` reset by the owner — never a silent retry.
|
|
31
27
|
*/
|
|
32
|
-
class AttachStateMachine {
|
|
33
|
-
|
|
34
|
-
this.current = 'disconnected';
|
|
35
|
-
}
|
|
28
|
+
export class AttachStateMachine {
|
|
29
|
+
current = 'disconnected';
|
|
36
30
|
/** The current state. */
|
|
37
31
|
get state() {
|
|
38
32
|
return this.current;
|
|
@@ -43,7 +37,7 @@ class AttachStateMachine {
|
|
|
43
37
|
*/
|
|
44
38
|
to(next) {
|
|
45
39
|
if (!LEGAL[this.current].includes(next)) {
|
|
46
|
-
throw new
|
|
40
|
+
throw new AttachError('UNKNOWN', `illegal attach-state transition ${this.current} → ${next}`);
|
|
47
41
|
}
|
|
48
42
|
this.current = next;
|
|
49
43
|
return this.current;
|
|
@@ -53,7 +47,6 @@ class AttachStateMachine {
|
|
|
53
47
|
return this.current === 'connecting' || this.current === 'navigating' || this.current === 'reading';
|
|
54
48
|
}
|
|
55
49
|
}
|
|
56
|
-
exports.AttachStateMachine = AttachStateMachine;
|
|
57
50
|
/**
|
|
58
51
|
* Bound a transport promise with a hard deadline.
|
|
59
52
|
*
|
|
@@ -62,10 +55,10 @@ exports.AttachStateMachine = AttachStateMachine;
|
|
|
62
55
|
* @param label Operation label for the failure message.
|
|
63
56
|
* @throws {AttachError} `NAV_TIMEOUT` when the deadline expires first.
|
|
64
57
|
*/
|
|
65
|
-
async function withDeadline(p, ms, label) {
|
|
58
|
+
export async function withDeadline(p, ms, label) {
|
|
66
59
|
let timer;
|
|
67
60
|
const gate = new Promise((_, reject) => {
|
|
68
|
-
timer = setTimeout(() => reject(new
|
|
61
|
+
timer = setTimeout(() => reject(new AttachError('NAV_TIMEOUT', `${label} exceeded ${ms}ms deadline`)), ms);
|
|
69
62
|
});
|
|
70
63
|
try {
|
|
71
64
|
return await Promise.race([p, gate]);
|
package/dist/attach/state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/attach/state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/attach/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAW1C,MAAM,KAAK,GAA0D,MAAM,CAAC,MAAM,CAAC;IACjF,YAAY,EAAE,CAAC,YAAY,CAAC;IAC5B,UAAU,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,cAAc,CAAC;IAC/C,KAAK,EAAE,CAAC,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,QAAQ,CAAC;IAC1D,UAAU,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC/B,OAAO,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC5B,MAAM,EAAE,CAAC,cAAc,CAAC;CACzB,CAAC,CAAC;AAEH;;;;;;GAMG;AACH,MAAM,OAAO,kBAAkB;IACrB,OAAO,GAAgB,cAAc,CAAC;IAE9C,yBAAyB;IACzB,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,EAAE,CAAC,IAAiB;QAClB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,MAAM,IAAI,WAAW,CAAC,SAAS,EAAE,mCAAmC,IAAI,CAAC,OAAO,MAAM,IAAI,EAAE,CAAC,CAAC;QAChG,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,kEAAkE;IAClE,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,KAAK,YAAY,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC;IACtG,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAI,CAAa,EAAE,EAAU,EAAE,KAAa;IAC5E,IAAI,KAAgD,CAAC;IACrD,MAAM,IAAI,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE;QAC5C,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,WAAW,CAAC,aAAa,EAAE,GAAG,KAAK,aAAa,EAAE,aAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7G,CAAC,CAAC,CAAC;IACH,IAAI,CAAC;QACH,OAAO,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACvC,CAAC;YAAS,CAAC;QACT,IAAI,KAAK;YAAE,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;AACH,CAAC"}
|
package/dist/attach/tools.d.ts
CHANGED
|
@@ -138,6 +138,46 @@ export declare class AttachReadTool {
|
|
|
138
138
|
data?: undefined;
|
|
139
139
|
}>;
|
|
140
140
|
}
|
|
141
|
+
/** `browser_attach_screenshot` — PNG evidence capture of the agent tab (CDP only). */
|
|
142
|
+
export declare class AttachScreenshotTool {
|
|
143
|
+
private controller;
|
|
144
|
+
readonly id = "browser_attach_screenshot";
|
|
145
|
+
readonly name = "browser_attach_screenshot";
|
|
146
|
+
readonly displayName = "Attach: screenshot";
|
|
147
|
+
readonly description = "Capture a PNG screenshot of the agent tab to a new file in the evidence directory \u2014 visual evidence for a research report. The result gives the path written. Requires the CDP transport (the AppleScript/JXA transport has no pixel access and refuses with UNSUPPORTED_OP). Never navigates or mutates the page; it writes one file, and never replaces one.";
|
|
148
|
+
readonly category = "browser";
|
|
149
|
+
readonly version = "0.1.0";
|
|
150
|
+
readonly hasSideEffects = true;
|
|
151
|
+
readonly inputSchema: {
|
|
152
|
+
type: "object";
|
|
153
|
+
properties: {
|
|
154
|
+
path: {
|
|
155
|
+
type: string;
|
|
156
|
+
description: string;
|
|
157
|
+
};
|
|
158
|
+
fullPage: {
|
|
159
|
+
type: string;
|
|
160
|
+
description: string;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
required: string[];
|
|
164
|
+
};
|
|
165
|
+
constructor(controller: AttachSurface);
|
|
166
|
+
execute(args: {
|
|
167
|
+
path: string;
|
|
168
|
+
fullPage?: boolean;
|
|
169
|
+
}): Promise<{
|
|
170
|
+
success: boolean;
|
|
171
|
+
data: any;
|
|
172
|
+
error?: undefined;
|
|
173
|
+
code?: undefined;
|
|
174
|
+
} | {
|
|
175
|
+
success: boolean;
|
|
176
|
+
error: string;
|
|
177
|
+
code: import("./errors.js").AttachErrorCode;
|
|
178
|
+
data?: undefined;
|
|
179
|
+
}>;
|
|
180
|
+
}
|
|
141
181
|
/** `browser_attach_release` — park + release the lease (no browser teardown). */
|
|
142
182
|
export declare class AttachReleaseTool {
|
|
143
183
|
private controller;
|
|
@@ -202,7 +242,7 @@ export declare class AttachControlTool {
|
|
|
202
242
|
}>;
|
|
203
243
|
}
|
|
204
244
|
/** Instantiate the full attach tool set sharing one controller. */
|
|
205
|
-
export declare function createAttachTools(controller: AttachSurface): (AttachStatusTool | AttachClaimTool | AttachGotoTool | AttachReadTool | AttachReleaseTool | AttachControlTool)[];
|
|
245
|
+
export declare function createAttachTools(controller: AttachSurface): (AttachStatusTool | AttachClaimTool | AttachGotoTool | AttachReadTool | AttachScreenshotTool | AttachReleaseTool | AttachControlTool)[];
|
|
206
246
|
/** All attach tool ids (for registry/policy classification). */
|
|
207
|
-
export declare const ATTACH_TOOL_IDS: readonly ["browser_attach_status", "browser_attach_claim", "browser_attach_goto", "browser_attach_read", "browser_attach_release", "browser_attach_control"];
|
|
247
|
+
export declare const ATTACH_TOOL_IDS: readonly ["browser_attach_status", "browser_attach_claim", "browser_attach_goto", "browser_attach_read", "browser_attach_screenshot", "browser_attach_release", "browser_attach_control"];
|
|
208
248
|
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/attach/tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/attach/tools.ts"],"names":[],"mappings":"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"}
|