pi-agent-browser-native 0.2.11 → 0.2.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/CHANGELOG.md +14 -3
- package/README.md +87 -27
- package/docs/ARCHITECTURE.md +9 -3
- package/docs/COMMAND_REFERENCE.md +383 -151
- package/docs/RELEASE.md +81 -26
- package/docs/REQUIREMENTS.md +10 -4
- package/docs/TOOL_CONTRACT.md +51 -11
- package/extensions/agent-browser/index.ts +845 -343
- package/extensions/agent-browser/lib/parsing.ts +20 -0
- package/extensions/agent-browser/lib/playbook.ts +79 -0
- package/extensions/agent-browser/lib/process.ts +56 -8
- package/extensions/agent-browser/lib/results/confirmation.ts +76 -0
- package/extensions/agent-browser/lib/results/envelope.ts +42 -5
- package/extensions/agent-browser/lib/results/presentation.ts +907 -50
- package/extensions/agent-browser/lib/results/shared.ts +166 -15
- package/extensions/agent-browser/lib/results/snapshot.ts +69 -7
- package/extensions/agent-browser/lib/results.ts +7 -1
- package/extensions/agent-browser/lib/runtime.ts +204 -15
- package/extensions/agent-browser/lib/temp.ts +131 -23
- package/package.json +11 -8
- package/scripts/agent-browser-capability-baseline.mjs +104 -0
- package/scripts/doctor.mjs +420 -0
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
* Invariants/Assumptions: Temp artifacts live under the OS temp directory, each active run uses a dedicated 0700 directory, files are created with exclusive 0600 permissions, session-scoped persisted artifacts stay under the pi session directory, and stale pruning only touches roots with an explicit pi-agent-browser ownership marker.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
9
10
|
import { randomBytes } from "node:crypto";
|
|
10
11
|
import { rmSync } from "node:fs";
|
|
11
12
|
import { chmod, mkdir, mkdtemp, open, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
12
13
|
import { tmpdir } from "node:os";
|
|
13
14
|
import { dirname, join } from "node:path";
|
|
15
|
+
import { promisify } from "node:util";
|
|
16
|
+
|
|
17
|
+
import { isRecord, parsePositiveInteger } from "./parsing.js";
|
|
14
18
|
|
|
15
19
|
const TEMP_ROOT_PREFIX = "pi-agent-browser-";
|
|
16
20
|
const TEMP_ROOT_MARKER_FILE_NAME = ".pi-agent-browser-owner.json";
|
|
@@ -22,6 +26,8 @@ const DEFAULT_TEMP_ROOT_MAX_BYTES = 32 * 1_024 * 1_024;
|
|
|
22
26
|
const SESSION_ARTIFACT_MAX_BYTES_ENV = "PI_AGENT_BROWSER_SESSION_ARTIFACT_MAX_BYTES";
|
|
23
27
|
const DEFAULT_SESSION_ARTIFACT_MAX_BYTES = 32 * 1_024 * 1_024;
|
|
24
28
|
const SESSION_ARTIFACTS_ROOT_DIR_NAME = ".pi-agent-browser-artifacts";
|
|
29
|
+
const PROCESS_START_IDENTITY_TIMEOUT_MS = 1_000;
|
|
30
|
+
const execFileAsync = promisify(execFile);
|
|
25
31
|
|
|
26
32
|
export interface PersistentSessionArtifactStore {
|
|
27
33
|
protectedPaths?: readonly string[];
|
|
@@ -29,40 +35,64 @@ export interface PersistentSessionArtifactStore {
|
|
|
29
35
|
sessionId: string;
|
|
30
36
|
}
|
|
31
37
|
|
|
38
|
+
export interface PersistentSessionArtifactEviction {
|
|
39
|
+
mtimeMs: number;
|
|
40
|
+
path: string;
|
|
41
|
+
sizeBytes: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PersistentSessionArtifactWriteResult {
|
|
45
|
+
evictedArtifacts: PersistentSessionArtifactEviction[];
|
|
46
|
+
path: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
interface TempRootOwnershipRecord {
|
|
33
50
|
createdAtMs: number;
|
|
34
51
|
kind: string;
|
|
52
|
+
leaseUpdatedAtMs?: number;
|
|
53
|
+
ownerPid?: number;
|
|
54
|
+
ownerProcessStartIdentity?: string;
|
|
35
55
|
ownerUid?: number;
|
|
36
56
|
version: number;
|
|
37
57
|
}
|
|
38
58
|
|
|
59
|
+
interface TempRootOwnershipMarkerOptions {
|
|
60
|
+
createdAtMs?: number;
|
|
61
|
+
leaseUpdatedAtMs?: number;
|
|
62
|
+
ownerPid?: number;
|
|
63
|
+
ownerProcessStartIdentity?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
type ProcessLiveness = "alive" | "dead" | "unknown";
|
|
67
|
+
|
|
39
68
|
let sessionTempRootPromise: Promise<string> | undefined;
|
|
40
69
|
let exitCleanupRegistered = false;
|
|
41
70
|
let tempMutationQueue = Promise.resolve();
|
|
42
71
|
const ownedTempRoots = new Set<string>();
|
|
43
72
|
|
|
44
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
45
|
-
return typeof value === "object" && value !== null;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
73
|
function getCurrentProcessUid(): number | undefined {
|
|
49
74
|
return typeof process.getuid === "function" ? process.getuid() : undefined;
|
|
50
75
|
}
|
|
51
76
|
|
|
52
|
-
function
|
|
53
|
-
|
|
54
|
-
const normalizedValue = rawValue.trim();
|
|
55
|
-
if (!/^\d+$/.test(normalizedValue)) return undefined;
|
|
56
|
-
const parsedValue = Number(normalizedValue);
|
|
57
|
-
if (!Number.isSafeInteger(parsedValue) || parsedValue <= 0) return undefined;
|
|
58
|
-
return parsedValue;
|
|
77
|
+
function isPositiveFiniteNumber(value: unknown): value is number {
|
|
78
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
function isTempRootOwnershipRecord(value: unknown): value is TempRootOwnershipRecord {
|
|
62
82
|
if (!isRecord(value)) return false;
|
|
63
83
|
if (value.kind !== TEMP_ROOT_MARKER_KIND || value.version !== TEMP_ROOT_MARKER_VERSION) return false;
|
|
64
|
-
if (
|
|
65
|
-
|
|
84
|
+
if (!isPositiveFiniteNumber(value.createdAtMs)) return false;
|
|
85
|
+
if (value.leaseUpdatedAtMs !== undefined && !isPositiveFiniteNumber(value.leaseUpdatedAtMs)) return false;
|
|
86
|
+
if (value.ownerPid !== undefined) {
|
|
87
|
+
if (typeof value.ownerPid !== "number" || !Number.isSafeInteger(value.ownerPid) || value.ownerPid <= 0) return false;
|
|
88
|
+
}
|
|
89
|
+
if (value.ownerProcessStartIdentity !== undefined) {
|
|
90
|
+
if (typeof value.ownerProcessStartIdentity !== "string" || value.ownerProcessStartIdentity.trim() === "") return false;
|
|
91
|
+
}
|
|
92
|
+
if (value.ownerUid !== undefined) {
|
|
93
|
+
if (typeof value.ownerUid !== "number" || !Number.isSafeInteger(value.ownerUid) || value.ownerUid < 0) return false;
|
|
94
|
+
}
|
|
95
|
+
return true;
|
|
66
96
|
}
|
|
67
97
|
|
|
68
98
|
function getTempArtifactByteLength(content: string | Uint8Array): number {
|
|
@@ -107,11 +137,33 @@ async function readTempRootOwnershipMarker(tempRoot: string): Promise<TempRootOw
|
|
|
107
137
|
}
|
|
108
138
|
}
|
|
109
139
|
|
|
110
|
-
|
|
140
|
+
async function getProcessStartIdentity(pid: number | undefined): Promise<string | undefined> {
|
|
141
|
+
if (pid === undefined) return undefined;
|
|
142
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return undefined;
|
|
143
|
+
try {
|
|
144
|
+
const { stdout } = await execFileAsync("ps", ["-p", String(pid), "-o", "lstart="], {
|
|
145
|
+
timeout: PROCESS_START_IDENTITY_TIMEOUT_MS,
|
|
146
|
+
});
|
|
147
|
+
const identity = stdout.trim().replace(/\s+/g, " ");
|
|
148
|
+
return identity || undefined;
|
|
149
|
+
} catch {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function writeSecureTempRootOwnershipMarker(
|
|
155
|
+
tempRoot: string,
|
|
156
|
+
options: TempRootOwnershipMarkerOptions = {},
|
|
157
|
+
): Promise<string> {
|
|
111
158
|
const markerPath = join(tempRoot, TEMP_ROOT_MARKER_FILE_NAME);
|
|
159
|
+
const createdAtMs = options.createdAtMs ?? Date.now();
|
|
160
|
+
const ownerPid = options.ownerPid ?? process.pid;
|
|
112
161
|
const markerRecord: TempRootOwnershipRecord = {
|
|
113
162
|
createdAtMs,
|
|
114
163
|
kind: TEMP_ROOT_MARKER_KIND,
|
|
164
|
+
leaseUpdatedAtMs: options.leaseUpdatedAtMs ?? createdAtMs,
|
|
165
|
+
ownerPid,
|
|
166
|
+
ownerProcessStartIdentity: options.ownerProcessStartIdentity ?? (await getProcessStartIdentity(ownerPid)),
|
|
115
167
|
ownerUid: getCurrentProcessUid(),
|
|
116
168
|
version: TEMP_ROOT_MARKER_VERSION,
|
|
117
169
|
};
|
|
@@ -120,6 +172,54 @@ export async function writeSecureTempRootOwnershipMarker(tempRoot: string, creat
|
|
|
120
172
|
return markerPath;
|
|
121
173
|
}
|
|
122
174
|
|
|
175
|
+
async function refreshSecureTempRootLease(tempRoot: string): Promise<void> {
|
|
176
|
+
const markerPath = join(tempRoot, TEMP_ROOT_MARKER_FILE_NAME);
|
|
177
|
+
const ownershipMarker = await readTempRootOwnershipMarker(tempRoot);
|
|
178
|
+
if (!ownershipMarker) return;
|
|
179
|
+
if (ownershipMarker.ownerPid !== process.pid) return;
|
|
180
|
+
const currentUid = getCurrentProcessUid();
|
|
181
|
+
if (currentUid !== undefined && ownershipMarker.ownerUid !== undefined && ownershipMarker.ownerUid !== currentUid) return;
|
|
182
|
+
const currentProcessStartIdentity = await getProcessStartIdentity(process.pid);
|
|
183
|
+
if (
|
|
184
|
+
ownershipMarker.ownerProcessStartIdentity !== undefined &&
|
|
185
|
+
currentProcessStartIdentity !== undefined &&
|
|
186
|
+
ownershipMarker.ownerProcessStartIdentity !== currentProcessStartIdentity
|
|
187
|
+
) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const refreshedMarker: TempRootOwnershipRecord = {
|
|
191
|
+
...ownershipMarker,
|
|
192
|
+
leaseUpdatedAtMs: Date.now(),
|
|
193
|
+
ownerPid: process.pid,
|
|
194
|
+
ownerProcessStartIdentity: currentProcessStartIdentity ?? ownershipMarker.ownerProcessStartIdentity,
|
|
195
|
+
ownerUid: currentUid,
|
|
196
|
+
};
|
|
197
|
+
await writeFile(markerPath, JSON.stringify(refreshedMarker, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
198
|
+
await chmod(markerPath, 0o600).catch(() => undefined);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function getMarkerOwnerLiveness(ownershipMarker: TempRootOwnershipRecord): Promise<ProcessLiveness> {
|
|
202
|
+
const pid = ownershipMarker.ownerPid;
|
|
203
|
+
if (pid === undefined) return "unknown";
|
|
204
|
+
try {
|
|
205
|
+
process.kill(pid, 0);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
const errorWithCode = error as NodeJS.ErrnoException;
|
|
208
|
+
if (errorWithCode.code === "ESRCH") return "dead";
|
|
209
|
+
if (errorWithCode.code !== "EPERM") return "unknown";
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const currentProcessStartIdentity = await getProcessStartIdentity(pid);
|
|
213
|
+
if (
|
|
214
|
+
ownershipMarker.ownerProcessStartIdentity !== undefined &&
|
|
215
|
+
currentProcessStartIdentity !== undefined &&
|
|
216
|
+
ownershipMarker.ownerProcessStartIdentity === currentProcessStartIdentity
|
|
217
|
+
) {
|
|
218
|
+
return "alive";
|
|
219
|
+
}
|
|
220
|
+
return "dead";
|
|
221
|
+
}
|
|
222
|
+
|
|
123
223
|
async function pruneStaleTempRoots(currentTempRoot: string | undefined): Promise<void> {
|
|
124
224
|
const entries = await readdir(tmpdir(), { withFileTypes: true }).catch(() => []);
|
|
125
225
|
const cutoffTime = Date.now() - STALE_TEMP_ROOT_MAX_AGE_MS;
|
|
@@ -141,9 +241,12 @@ async function pruneStaleTempRoots(currentTempRoot: string | undefined): Promise
|
|
|
141
241
|
) {
|
|
142
242
|
return;
|
|
143
243
|
}
|
|
244
|
+
const staleTimestampMs = ownershipMarker.leaseUpdatedAtMs ?? ownershipMarker.createdAtMs;
|
|
245
|
+
if (staleTimestampMs >= cutoffTime) return;
|
|
246
|
+
if ((await getMarkerOwnerLiveness(ownershipMarker)) === "alive") return;
|
|
144
247
|
|
|
145
248
|
const stats = await stat(path).catch(() => undefined);
|
|
146
|
-
if (!stats?.isDirectory()
|
|
249
|
+
if (!stats?.isDirectory()) return;
|
|
147
250
|
await rm(path, { force: true, recursive: true }).catch(() => undefined);
|
|
148
251
|
}),
|
|
149
252
|
);
|
|
@@ -205,23 +308,25 @@ async function prunePersistentSessionArtifactsToBudget(
|
|
|
205
308
|
sessionArtifactDir: string,
|
|
206
309
|
additionalBytes: number,
|
|
207
310
|
protectedPaths: ReadonlySet<string>,
|
|
208
|
-
): Promise<
|
|
209
|
-
if (additionalBytes <= 0) return;
|
|
311
|
+
): Promise<PersistentSessionArtifactEviction[]> {
|
|
312
|
+
if (additionalBytes <= 0) return [];
|
|
210
313
|
const maxBytes = getPersistentSessionArtifactMaxBytes();
|
|
211
314
|
let files = await listArtifactFiles(sessionArtifactDir);
|
|
212
315
|
let totalBytes = files.reduce((total, file) => total + file.size, 0);
|
|
213
316
|
if (totalBytes + additionalBytes <= maxBytes) {
|
|
214
|
-
return;
|
|
317
|
+
return [];
|
|
215
318
|
}
|
|
319
|
+
const evictedArtifacts: PersistentSessionArtifactEviction[] = [];
|
|
216
320
|
files = files.sort((left, right) => left.mtimeMs - right.mtimeMs || left.path.localeCompare(right.path));
|
|
217
321
|
for (const file of files) {
|
|
218
322
|
if (protectedPaths.has(file.path)) {
|
|
219
323
|
continue;
|
|
220
324
|
}
|
|
221
325
|
await rm(file.path, { force: true }).catch(() => undefined);
|
|
326
|
+
evictedArtifacts.push({ mtimeMs: file.mtimeMs, path: file.path, sizeBytes: file.size });
|
|
222
327
|
totalBytes -= file.size;
|
|
223
328
|
if (totalBytes + additionalBytes <= maxBytes) {
|
|
224
|
-
return;
|
|
329
|
+
return evictedArtifacts;
|
|
225
330
|
}
|
|
226
331
|
}
|
|
227
332
|
throw new Error(`pi-agent-browser persisted spill budget exceeded (${totalBytes + additionalBytes} bytes > ${maxBytes} byte limit).`);
|
|
@@ -241,6 +346,7 @@ async function getSessionTempRoot(): Promise<string> {
|
|
|
241
346
|
}
|
|
242
347
|
|
|
243
348
|
const tempRoot = await sessionTempRootPromise;
|
|
349
|
+
await refreshSecureTempRootLease(tempRoot).catch(() => undefined);
|
|
244
350
|
await pruneStaleTempRoots(tempRoot).catch(() => undefined);
|
|
245
351
|
return tempRoot;
|
|
246
352
|
}
|
|
@@ -259,7 +365,9 @@ export async function writeSecureTempChunk(options: {
|
|
|
259
365
|
}): Promise<void> {
|
|
260
366
|
const { content, fileHandle, path } = options;
|
|
261
367
|
await enqueueTempMutation(async () => {
|
|
262
|
-
|
|
368
|
+
const tempRoot = dirname(path);
|
|
369
|
+
await refreshSecureTempRootLease(tempRoot).catch(() => undefined);
|
|
370
|
+
await assertSecureTempRootBudget(tempRoot, getTempArtifactByteLength(content));
|
|
263
371
|
await fileHandle.appendFile(content);
|
|
264
372
|
});
|
|
265
373
|
}
|
|
@@ -287,11 +395,11 @@ export async function writePersistentSessionArtifactFile(options: {
|
|
|
287
395
|
prefix: string;
|
|
288
396
|
store: PersistentSessionArtifactStore;
|
|
289
397
|
suffix: string;
|
|
290
|
-
}): Promise<
|
|
398
|
+
}): Promise<PersistentSessionArtifactWriteResult> {
|
|
291
399
|
const { content, prefix, store, suffix } = options;
|
|
292
400
|
return await enqueueTempMutation(async () => {
|
|
293
401
|
const artifactDir = await ensurePersistentSessionArtifactDir(store);
|
|
294
|
-
await prunePersistentSessionArtifactsToBudget(
|
|
402
|
+
const evictedArtifacts = await prunePersistentSessionArtifactsToBudget(
|
|
295
403
|
artifactDir,
|
|
296
404
|
getTempArtifactByteLength(content),
|
|
297
405
|
new Set((store.protectedPaths ?? []).filter((path) => dirname(path) === artifactDir)),
|
|
@@ -306,7 +414,7 @@ export async function writePersistentSessionArtifactFile(options: {
|
|
|
306
414
|
} finally {
|
|
307
415
|
await fileHandle.close().catch(() => undefined);
|
|
308
416
|
}
|
|
309
|
-
return path;
|
|
417
|
+
return { evictedArtifacts, path };
|
|
310
418
|
});
|
|
311
419
|
}
|
|
312
420
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-browser-native",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
4
4
|
"description": "pi extension that exposes agent-browser as a native tool for browser automation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "Mitch Fultz (https://github.com/fitchmultz)",
|
|
@@ -26,8 +26,13 @@
|
|
|
26
26
|
"engines": {
|
|
27
27
|
"node": ">=20.6.0"
|
|
28
28
|
},
|
|
29
|
+
"bin": {
|
|
30
|
+
"pi-agent-browser-doctor": "scripts/doctor.mjs"
|
|
31
|
+
},
|
|
29
32
|
"files": [
|
|
30
33
|
"extensions",
|
|
34
|
+
"scripts/doctor.mjs",
|
|
35
|
+
"scripts/agent-browser-capability-baseline.mjs",
|
|
31
36
|
"README.md",
|
|
32
37
|
"CHANGELOG.md",
|
|
33
38
|
"LICENSE",
|
|
@@ -46,22 +51,20 @@
|
|
|
46
51
|
"typebox": "*"
|
|
47
52
|
},
|
|
48
53
|
"devDependencies": {
|
|
49
|
-
"@mariozechner/pi-coding-agent": "^0.
|
|
54
|
+
"@mariozechner/pi-coding-agent": "^0.70.0",
|
|
50
55
|
"@types/node": "^25.6.0",
|
|
51
56
|
"tsx": "^4.21.0",
|
|
52
|
-
"typebox": "^1.1.
|
|
57
|
+
"typebox": "^1.1.33",
|
|
53
58
|
"typescript": "^6.0.3"
|
|
54
59
|
},
|
|
55
60
|
"overrides": {
|
|
56
61
|
"basic-ftp": "5.3.0"
|
|
57
62
|
},
|
|
58
63
|
"scripts": {
|
|
59
|
-
"
|
|
64
|
+
"docs": "node ./scripts/project.mjs docs",
|
|
65
|
+
"doctor": "node ./scripts/doctor.mjs",
|
|
60
66
|
"test": "tsx --test test/**/*.test.ts",
|
|
61
|
-
"
|
|
62
|
-
"verify": "npm run typecheck && npm run test",
|
|
63
|
-
"verify:package": "node ./scripts/verify-package.mjs",
|
|
64
|
-
"verify:release": "npm run verify && npm run verify:package"
|
|
67
|
+
"verify": "node ./scripts/project.mjs verify"
|
|
65
68
|
},
|
|
66
69
|
"packageManager": "npm@10.9.8"
|
|
67
70
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Purpose: Define the canonical upstream agent-browser capability baseline targeted by this package.
|
|
3
|
+
* Responsibilities: Store the target upstream version, sampled help commands, and verifier/doc token expectations in one importable metadata object.
|
|
4
|
+
* Scope: Versioned capability metadata only; it does not execute agent-browser or validate documentation by itself.
|
|
5
|
+
* Usage: Imported by command-reference verifier, generated docs checker, and tests when upstream agent-browser is re-baselined.
|
|
6
|
+
* Invariants/Assumptions: This package targets the current installed upstream agent-browser only and does not keep compatibility shims for older versions.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const CAPABILITY_BASELINE_SOURCE = "scripts/agent-browser-capability-baseline.mjs";
|
|
10
|
+
export const COMMAND_REFERENCE_DOC_PATH = "docs/COMMAND_REFERENCE.md";
|
|
11
|
+
export const CAPABILITY_BASELINE_BLOCK_MARKER_PREFIX = "agent-browser-capability-baseline";
|
|
12
|
+
export const COMMAND_REFERENCE_BASELINE_BLOCK_IDS = Object.freeze(["upstream-baseline", "capability-token-baseline"]);
|
|
13
|
+
|
|
14
|
+
export const CAPABILITY_BASELINE = Object.freeze({
|
|
15
|
+
targetVersion: "0.26.0",
|
|
16
|
+
helpCommands: Object.freeze([
|
|
17
|
+
Object.freeze({ label: "root help", args: Object.freeze(["--help"]) }),
|
|
18
|
+
Object.freeze({ label: "tab help", args: Object.freeze(["tab", "--help"]) }),
|
|
19
|
+
Object.freeze({ label: "snapshot help", args: Object.freeze(["snapshot", "--help"]) }),
|
|
20
|
+
Object.freeze({ label: "wait help", args: Object.freeze(["wait", "--help"]) }),
|
|
21
|
+
]),
|
|
22
|
+
docRequiredTokens: Object.freeze([
|
|
23
|
+
"skills list",
|
|
24
|
+
"skills get core --full",
|
|
25
|
+
"keyboard type <text>",
|
|
26
|
+
"scroll <dir> [px]",
|
|
27
|
+
"scrollintoview <sel>",
|
|
28
|
+
"connect <port|url>",
|
|
29
|
+
"is <what> <selector>",
|
|
30
|
+
"find <locator> <value> <action>",
|
|
31
|
+
"mouse <action> [args]",
|
|
32
|
+
"set <setting> [value]",
|
|
33
|
+
"network <action>",
|
|
34
|
+
"cookies [get|set|clear]",
|
|
35
|
+
"storage <local|session>",
|
|
36
|
+
"diff snapshot",
|
|
37
|
+
"trace start|stop [path]",
|
|
38
|
+
"profiler start|stop [path]",
|
|
39
|
+
"record start <path> [url]",
|
|
40
|
+
"console [--clear]",
|
|
41
|
+
"errors [--clear]",
|
|
42
|
+
"highlight <sel>",
|
|
43
|
+
"inspect",
|
|
44
|
+
"clipboard <op> [text]",
|
|
45
|
+
"stream enable [--port <n>]",
|
|
46
|
+
"auth save <name>",
|
|
47
|
+
"confirm <id>",
|
|
48
|
+
"deny <id>",
|
|
49
|
+
"chat <message>",
|
|
50
|
+
"dashboard start --port <n>",
|
|
51
|
+
"install --with-deps",
|
|
52
|
+
"upgrade",
|
|
53
|
+
"doctor [--fix]",
|
|
54
|
+
"profiles",
|
|
55
|
+
"snapshot -i --urls",
|
|
56
|
+
"snapshot --urls",
|
|
57
|
+
"wait --download [path]",
|
|
58
|
+
"tab new --label <name> [url]",
|
|
59
|
+
"--action-policy <path>",
|
|
60
|
+
"--confirm-actions <list>",
|
|
61
|
+
"--engine <name>",
|
|
62
|
+
"AGENT_BROWSER_CONFIG",
|
|
63
|
+
]),
|
|
64
|
+
upstreamExpectations: Object.freeze([
|
|
65
|
+
Object.freeze({ token: "skills", help: "root help" }),
|
|
66
|
+
Object.freeze({ token: "keyboard", help: "root help" }),
|
|
67
|
+
Object.freeze({ token: "scroll", help: "root help" }),
|
|
68
|
+
Object.freeze({ token: "scrollintoview", help: "root help" }),
|
|
69
|
+
Object.freeze({ token: "connect", help: "root help" }),
|
|
70
|
+
Object.freeze({ token: "is", help: "root help" }),
|
|
71
|
+
Object.freeze({ token: "find", help: "root help" }),
|
|
72
|
+
Object.freeze({ token: "mouse", help: "root help" }),
|
|
73
|
+
Object.freeze({ token: "set", help: "root help" }),
|
|
74
|
+
Object.freeze({ token: "network", help: "root help" }),
|
|
75
|
+
Object.freeze({ token: "cookies [get|set|clear]", help: "root help" }),
|
|
76
|
+
Object.freeze({ token: "storage", help: "root help" }),
|
|
77
|
+
Object.freeze({ token: "diff snapshot", help: "root help" }),
|
|
78
|
+
Object.freeze({ token: "trace start|stop [path]", help: "root help" }),
|
|
79
|
+
Object.freeze({ token: "profiler start|stop [path]", help: "root help" }),
|
|
80
|
+
Object.freeze({ token: "record start <path> [url]", help: "root help" }),
|
|
81
|
+
Object.freeze({ token: "console [--clear]", help: "root help" }),
|
|
82
|
+
Object.freeze({ token: "errors [--clear]", help: "root help" }),
|
|
83
|
+
Object.freeze({ token: "highlight <sel>", help: "root help" }),
|
|
84
|
+
Object.freeze({ token: "inspect", help: "root help" }),
|
|
85
|
+
Object.freeze({ token: "clipboard <op> [text]", help: "root help" }),
|
|
86
|
+
Object.freeze({ token: "stream enable [--port <n>]", help: "root help" }),
|
|
87
|
+
Object.freeze({ token: "auth save <name>", help: "root help" }),
|
|
88
|
+
Object.freeze({ token: "confirm <id>", help: "root help" }),
|
|
89
|
+
Object.freeze({ token: "deny <id>", help: "root help" }),
|
|
90
|
+
Object.freeze({ token: "chat <message>", help: "root help" }),
|
|
91
|
+
Object.freeze({ token: "dashboard start --port <n>", help: "root help" }),
|
|
92
|
+
Object.freeze({ token: "install --with-deps", help: "root help" }),
|
|
93
|
+
Object.freeze({ token: "upgrade", help: "root help" }),
|
|
94
|
+
Object.freeze({ token: "doctor [--fix]", help: "root help" }),
|
|
95
|
+
Object.freeze({ token: "profiles", help: "root help" }),
|
|
96
|
+
Object.freeze({ token: "-u, --urls", help: "snapshot help" }),
|
|
97
|
+
Object.freeze({ token: "--download [path]", help: "wait help" }),
|
|
98
|
+
Object.freeze({ token: "new --label <name> [url]", help: "tab help" }),
|
|
99
|
+
]),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
export function expectedVersionLabel() {
|
|
103
|
+
return `agent-browser ${CAPABILITY_BASELINE.targetVersion}`;
|
|
104
|
+
}
|