pi-agent-browser-native 0.2.77 → 0.5.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/CHANGELOG.md +154 -0
- package/README.md +69 -35
- package/dist/extensions/agent-browser/index.js +911 -121
- package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -8
- package/dist/extensions/agent-browser/lib/argv-grammar.js +48 -7
- package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
- package/dist/extensions/agent-browser/lib/command-policy.js +1 -6
- package/dist/extensions/agent-browser/lib/command-taxonomy.js +35 -8
- package/dist/extensions/agent-browser/lib/config-policy.js +0 -5
- package/dist/extensions/agent-browser/lib/config.js +0 -6
- package/dist/extensions/agent-browser/lib/electron/cdp.js +6 -7
- package/dist/extensions/agent-browser/lib/electron/cleanup.js +0 -7
- package/dist/extensions/agent-browser/lib/electron/discovery.js +0 -7
- package/dist/extensions/agent-browser/lib/electron/launch.js +0 -7
- package/dist/extensions/agent-browser/lib/input-modes/electron.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -9
- package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -7
- package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -29
- package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
- package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -17
- package/dist/extensions/agent-browser/lib/input-modes/shared.js +0 -5
- package/dist/extensions/agent-browser/lib/input-modes/types.js +0 -5
- package/dist/extensions/agent-browser/lib/json-schema.js +0 -5
- package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +12 -5
- package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -2
- package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +3 -4
- package/dist/extensions/agent-browser/lib/managed-session-restore.js +55 -48
- package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -9
- package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +48 -36
- package/dist/extensions/agent-browser/lib/managed-session-storage.js +50 -29
- package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -5
- package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +27 -26
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +58 -33
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +22 -14
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +1 -1
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +148 -34
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +225 -61
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +74 -30
- package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +47 -26
- package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +40 -19
- package/dist/extensions/agent-browser/lib/orchestration/output-file.js +42 -1
- package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
- package/dist/extensions/agent-browser/lib/parsing.js +0 -7
- package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +36 -11
- package/dist/extensions/agent-browser/lib/playbook.js +20 -24
- package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
- package/dist/extensions/agent-browser/lib/process-identity.js +4 -9
- package/dist/extensions/agent-browser/lib/process.js +131 -48
- package/dist/extensions/agent-browser/lib/prompt-policy.js +171 -27
- package/dist/extensions/agent-browser/lib/recording-reservations.js +183 -0
- package/dist/extensions/agent-browser/lib/results/action-recommendations.js +63 -13
- package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +68 -11
- package/dist/extensions/agent-browser/lib/results/categories.js +7 -9
- package/dist/extensions/agent-browser/lib/results/confirmation.js +0 -7
- package/dist/extensions/agent-browser/lib/results/contracts.js +0 -7
- package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +0 -7
- package/dist/extensions/agent-browser/lib/results/envelope.js +0 -7
- package/dist/extensions/agent-browser/lib/results/network.js +0 -7
- package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -35
- package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -44
- package/dist/extensions/agent-browser/lib/results/presentation/batch.js +66 -11
- package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/common.js +18 -5
- package/dist/extensions/agent-browser/lib/results/presentation/content.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +7 -6
- package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
- package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +26 -16
- package/dist/extensions/agent-browser/lib/results/presentation/registry.js +58 -13
- package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -15
- package/dist/extensions/agent-browser/lib/results/presentation/skills.js +0 -5
- package/dist/extensions/agent-browser/lib/results/presentation.js +6 -8
- package/dist/extensions/agent-browser/lib/results/recovery-actions.js +2 -7
- package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +0 -7
- package/dist/extensions/agent-browser/lib/results/selector-recovery.js +51 -15
- package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -14
- package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +0 -7
- package/dist/extensions/agent-browser/lib/results/snapshot.js +0 -7
- package/dist/extensions/agent-browser/lib/results/text.js +0 -7
- package/dist/extensions/agent-browser/lib/runtime.js +119 -52
- package/dist/extensions/agent-browser/lib/session-page-state.js +62 -17
- package/dist/extensions/agent-browser/lib/string-enum-schema.js +0 -5
- package/dist/extensions/agent-browser/lib/temp.js +0 -7
- package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
- package/dist/extensions/agent-browser/lib/web-search.js +0 -5
- package/dist/extensions/agent-browser/script-worker.js +169 -0
- package/dist/scripts/agent-browser-target.mjs +3 -0
- package/docs/ARCHITECTURE.md +50 -31
- package/docs/COMMAND_REFERENCE.md +97 -41
- package/docs/ELECTRON.md +3 -19
- package/docs/RELEASE.md +8 -20
- package/docs/REQUIREMENTS.md +8 -6
- package/docs/SUPPORT_MATRIX.md +32 -25
- package/docs/TOOL_CONTRACT.md +107 -64
- package/docs/platform-smoke.md +1 -1
- package/package.json +7 -6
- package/platform-smoke.config.mjs +2 -2
- package/scripts/agent-browser-capability-baseline.mjs +24 -6
- package/scripts/agent-browser-target.mjs +3 -0
- package/scripts/build.mjs +41 -0
- package/scripts/doctor.mjs +8 -7
- package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
- package/scripts/platform-smoke/targets.mjs +12 -6
- package/dist/extensions/agent-browser/lib/electron/text.js +0 -13
- package/dist/extensions/agent-browser/lib/input-modes.js +0 -10
- package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +0 -5
- package/dist/extensions/agent-browser/lib/results/artifact-state.js +0 -13
- package/dist/extensions/agent-browser/lib/results.js +0 -14
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* Purpose: Parse raw agent-browser argv once into a stable command descriptor for planners and policy.
|
|
3
|
-
* Responsibilities: Own command-token extraction, command/subcommand identification, and descriptor construction.
|
|
4
|
-
* Scope: Pure argv parsing; runtime planning and session policy consume descriptors instead of re-parsing tokens.
|
|
5
|
-
*/
|
|
6
|
-
import { GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, VALUE_FLAGS, optionalGlobalValueFlagConsumesNext } from "./argv-grammar.js";
|
|
1
|
+
import { GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, VALUE_FLAGS, optionalGlobalValueFlagConsumesNext, stripUpstreamGlobalFlags } from "./argv-grammar.js";
|
|
7
2
|
import { isOpenNavigationCommand } from "./command-taxonomy.js";
|
|
8
3
|
function isBooleanLiteral(token) {
|
|
9
4
|
const normalized = token?.trim().toLowerCase();
|
|
@@ -38,6 +33,33 @@ export function extractCommandTokens(args) {
|
|
|
38
33
|
const commandStartIndex = findCommandStartIndex(args);
|
|
39
34
|
return commandStartIndex === undefined ? [] : args.slice(commandStartIndex);
|
|
40
35
|
}
|
|
36
|
+
export function extractUpstreamCommandTokens(args) {
|
|
37
|
+
return stripUpstreamGlobalFlags(extractCommandTokens(args));
|
|
38
|
+
}
|
|
39
|
+
export function parseWaitCommandTokens(commandTokens) {
|
|
40
|
+
if (commandTokens[0] !== "wait")
|
|
41
|
+
return {};
|
|
42
|
+
const considered = commandTokens.slice(1).map((token, offset) => ({ index: offset + 1, token }));
|
|
43
|
+
const timeoutIndex = considered.findIndex((entry) => entry.token === "--timeout");
|
|
44
|
+
if (timeoutIndex >= 0)
|
|
45
|
+
considered.splice(timeoutIndex, Math.min(2, considered.length - timeoutIndex));
|
|
46
|
+
for (const flags of [["--url", "-u"], ["--load", "-l"], ["--fn", "-f"], ["--text", "-t"]]) {
|
|
47
|
+
const match = considered.find((entry) => flags.includes(entry.token));
|
|
48
|
+
if (match)
|
|
49
|
+
return { subcommand: match.token };
|
|
50
|
+
}
|
|
51
|
+
const download = considered.find((entry) => entry.token === "--download" || entry.token === "-d");
|
|
52
|
+
if (download) {
|
|
53
|
+
const downloadPathIndex = download.index + 1;
|
|
54
|
+
const candidate = commandTokens[downloadPathIndex];
|
|
55
|
+
return {
|
|
56
|
+
downloadPath: candidate && !candidate.startsWith("--") ? candidate : undefined,
|
|
57
|
+
downloadPathIndex: candidate && !candidate.startsWith("--") ? downloadPathIndex : undefined,
|
|
58
|
+
subcommand: download.token,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return { subcommand: considered[0]?.token };
|
|
62
|
+
}
|
|
41
63
|
function getOpenCommandTarget(commandTokens) {
|
|
42
64
|
for (let index = 1; index < commandTokens.length; index += 1) {
|
|
43
65
|
const token = commandTokens[index];
|
|
@@ -56,10 +78,13 @@ function getOpenCommandTarget(commandTokens) {
|
|
|
56
78
|
return undefined;
|
|
57
79
|
}
|
|
58
80
|
export function parseCommandInfoFromTokens(commandTokens) {
|
|
59
|
-
const
|
|
81
|
+
const upstreamCommandTokens = stripUpstreamGlobalFlags(commandTokens);
|
|
82
|
+
const command = upstreamCommandTokens[0];
|
|
60
83
|
return {
|
|
61
84
|
command,
|
|
62
|
-
subcommand: isOpenNavigationCommand(command)
|
|
85
|
+
subcommand: isOpenNavigationCommand(command)
|
|
86
|
+
? getOpenCommandTarget(upstreamCommandTokens)
|
|
87
|
+
: command === "wait" ? parseWaitCommandTokens(upstreamCommandTokens).subcommand : upstreamCommandTokens[1],
|
|
63
88
|
};
|
|
64
89
|
}
|
|
65
90
|
export function parseCommandInfo(args) {
|
|
@@ -67,8 +92,10 @@ export function parseCommandInfo(args) {
|
|
|
67
92
|
}
|
|
68
93
|
export function parseArgvDescriptor(args) {
|
|
69
94
|
const commandTokens = extractCommandTokens(args);
|
|
95
|
+
const upstreamCommandTokens = stripUpstreamGlobalFlags(commandTokens);
|
|
70
96
|
return {
|
|
71
97
|
commandInfo: parseCommandInfoFromTokens(commandTokens),
|
|
72
98
|
commandTokens,
|
|
99
|
+
upstreamCommandTokens,
|
|
73
100
|
};
|
|
74
101
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Shared argv flag-shape metadata and helpers for command discovery and sessionless policy checks.
|
|
3
|
-
* Responsibilities: Own global/command value-flag sets and boolean/value-flag validation used during argv parsing.
|
|
4
|
-
* Scope: Pure token grammar; command semantics and subprocess execution live elsewhere.
|
|
5
|
-
*/
|
|
6
1
|
import { isKnownCommandToken } from "./command-taxonomy.js";
|
|
7
2
|
export const GLOBAL_VALUE_FLAGS = [
|
|
8
3
|
"--session",
|
|
@@ -95,6 +90,11 @@ export const GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES = new Set([
|
|
|
95
90
|
"--ignore-https-errors",
|
|
96
91
|
"--json",
|
|
97
92
|
"--no-auto-dialog",
|
|
93
|
+
"--no-pin-tab",
|
|
94
|
+
"--offline",
|
|
95
|
+
"--pin-tab",
|
|
96
|
+
"--quick",
|
|
97
|
+
"--fix",
|
|
98
98
|
"--quiet",
|
|
99
99
|
"-q",
|
|
100
100
|
"--verbose",
|
|
@@ -125,6 +125,10 @@ export function getBooleanFlagValue(args, flag) {
|
|
|
125
125
|
export function isBooleanFlagEnabled(args, flag) {
|
|
126
126
|
return getBooleanFlagValue(args, flag) ?? false;
|
|
127
127
|
}
|
|
128
|
+
/** Match upstream env_var_is_truthy exactly: lowercase only, without trimming or accepting "off". */
|
|
129
|
+
export function isUpstreamEnvFlagEnabled(value) {
|
|
130
|
+
return value !== undefined && !["", "0", "false", "no"].includes(value.toLowerCase());
|
|
131
|
+
}
|
|
128
132
|
/** Mirror upstream sanitize_session_component for namespace/socket/state identity. */
|
|
129
133
|
export function canonicalizeAgentBrowserNamespace(value) {
|
|
130
134
|
if (value === undefined)
|
|
@@ -149,7 +153,7 @@ export function canonicalizeAgentBrowserNamespace(value) {
|
|
|
149
153
|
}
|
|
150
154
|
return normalized.replace(/[-_]+$/u, "") || undefined;
|
|
151
155
|
}
|
|
152
|
-
function foldAgentBrowserFilesystemIdentity(value, platform) {
|
|
156
|
+
export function foldAgentBrowserFilesystemIdentity(value, platform) {
|
|
153
157
|
if (platform !== "darwin" && platform !== "win32")
|
|
154
158
|
return value;
|
|
155
159
|
// APFS aliases include full Unicode folds such as ß/SS and ς/Σ, not just ASCII case.
|
|
@@ -161,7 +165,11 @@ export function getAgentBrowserSessionIdentityKey(sessionName, namespace, platfo
|
|
|
161
165
|
const canonicalSessionName = foldAgentBrowserFilesystemIdentity(sessionName, platform);
|
|
162
166
|
return identityNamespace ? `${identityNamespace}\0${canonicalSessionName}` : canonicalSessionName;
|
|
163
167
|
}
|
|
164
|
-
|
|
168
|
+
export function isAgentBrowserSessionIdentityKeyInNamespace(identityKey, namespace) {
|
|
169
|
+
const prefix = getAgentBrowserSessionIdentityKey("", namespace);
|
|
170
|
+
return prefix ? identityKey.startsWith(prefix) : !identityKey.includes("\0");
|
|
171
|
+
}
|
|
172
|
+
/** Mirror upstream 0.34.0 global parsing: full argv, no `--` sentinel, and only global value payloads are skipped. */
|
|
165
173
|
export function scanUpstreamGlobalFlagOccurrences(args, targetFlag) {
|
|
166
174
|
const occurrences = [];
|
|
167
175
|
for (let index = 0; index < args.length; index += 1) {
|
|
@@ -258,6 +266,39 @@ export function optionalGlobalValueFlagConsumesNext(flag, nextToken) {
|
|
|
258
266
|
return false;
|
|
259
267
|
return !isKnownCommandToken(nextToken);
|
|
260
268
|
}
|
|
269
|
+
export function projectUpstreamGlobalFlags(args) {
|
|
270
|
+
const indices = [];
|
|
271
|
+
const tokens = [];
|
|
272
|
+
let seenCommand = false;
|
|
273
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
274
|
+
const token = args[index];
|
|
275
|
+
if (token.startsWith("--restore="))
|
|
276
|
+
continue;
|
|
277
|
+
if (token === "--restore") {
|
|
278
|
+
if (!seenCommand && optionalGlobalValueFlagConsumesNext(token, args[index + 1]))
|
|
279
|
+
index += 1;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (PREVALIDATED_VALUE_FLAGS.has(token)) {
|
|
283
|
+
index += 1;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES.has(token)) {
|
|
287
|
+
if (["true", "false"].includes(args[index + 1] ?? ""))
|
|
288
|
+
index += 1;
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
tokens.push(token);
|
|
292
|
+
indices.push(index);
|
|
293
|
+
if (isKnownCommandToken(token))
|
|
294
|
+
seenCommand = true;
|
|
295
|
+
}
|
|
296
|
+
return { indices, tokens };
|
|
297
|
+
}
|
|
298
|
+
/** Mirror upstream 0.34.0 clean_args: remove global flags wherever they appear before command parsing. */
|
|
299
|
+
export function stripUpstreamGlobalFlags(args) {
|
|
300
|
+
return projectUpstreamGlobalFlags(args).tokens;
|
|
301
|
+
}
|
|
261
302
|
export function stripSessionlessShapeGlobalFlags(commandTokens) {
|
|
262
303
|
const stripped = [];
|
|
263
304
|
for (let index = 0; index < commandTokens.length; index += 1) {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { extractUpstreamCommandTokens } from "./argv-descriptor.js";
|
|
2
|
+
import { isCloseAllCommand, isCloseCommand } from "./command-taxonomy.js";
|
|
3
|
+
import { isRecord } from "./parsing.js";
|
|
4
|
+
function getRowBrowserLaunched(row) {
|
|
5
|
+
const result = isRecord(row.result) ? row.result : isRecord(row.data) ? row.data : undefined;
|
|
6
|
+
const lifecycle = isRecord(row.lifecycle) ? row.lifecycle : isRecord(result?.lifecycle) ? result.lifecycle : undefined;
|
|
7
|
+
const effectiveLaunch = isRecord(lifecycle?.effectiveLaunch) ? lifecycle.effectiveLaunch : undefined;
|
|
8
|
+
return typeof effectiveLaunch?.browserLaunched === "boolean" ? effectiveLaunch.browserLaunched : undefined;
|
|
9
|
+
}
|
|
10
|
+
export function batchHasSuccessfulCloseAll(data, fallbackCommands = []) {
|
|
11
|
+
if (!Array.isArray(data))
|
|
12
|
+
return false;
|
|
13
|
+
return data.some((row, index) => {
|
|
14
|
+
if (!isRecord(row) || row.success !== true)
|
|
15
|
+
return false;
|
|
16
|
+
const rowCommand = Array.isArray(row.command) && row.command.every((token) => typeof token === "string")
|
|
17
|
+
? row.command
|
|
18
|
+
: fallbackCommands[index];
|
|
19
|
+
return rowCommand ? isCloseAllCommand(extractUpstreamCommandTokens(rowCommand)) : false;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export function getSuccessfulBatchCloseLifecycle(rows, fallbackCommands = []) {
|
|
23
|
+
if (!Array.isArray(rows))
|
|
24
|
+
return undefined;
|
|
25
|
+
let sawClose = false;
|
|
26
|
+
let endsClosed = false;
|
|
27
|
+
let browserActiveAfterClose = false;
|
|
28
|
+
let recordingClosedAfterBatch = false;
|
|
29
|
+
let statePath;
|
|
30
|
+
for (const [index, row] of rows.entries()) {
|
|
31
|
+
if (!isRecord(row))
|
|
32
|
+
continue;
|
|
33
|
+
const stepSucceeded = row.success === true;
|
|
34
|
+
const rowCommand = Array.isArray(row.command) && row.command.every((token) => typeof token === "string")
|
|
35
|
+
? row.command
|
|
36
|
+
: fallbackCommands[index];
|
|
37
|
+
const browserLaunched = getRowBrowserLaunched(row);
|
|
38
|
+
if (!rowCommand) {
|
|
39
|
+
if (sawClose && browserLaunched !== false) {
|
|
40
|
+
endsClosed = false;
|
|
41
|
+
browserActiveAfterClose = true;
|
|
42
|
+
recordingClosedAfterBatch = false;
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const [command, subcommand] = extractUpstreamCommandTokens(rowCommand);
|
|
47
|
+
if (stepSucceeded && isCloseCommand(command)) {
|
|
48
|
+
sawClose = true;
|
|
49
|
+
endsClosed = true;
|
|
50
|
+
browserActiveAfterClose = false;
|
|
51
|
+
recordingClosedAfterBatch = true;
|
|
52
|
+
const result = isRecord(row.result) ? row.result : isRecord(row.data) ? row.data : undefined;
|
|
53
|
+
statePath = typeof result?.statePath === "string" ? result.statePath : undefined;
|
|
54
|
+
}
|
|
55
|
+
else if (sawClose && command === "record") {
|
|
56
|
+
if (browserLaunched === true || (subcommand === "stop" && browserLaunched === undefined)) {
|
|
57
|
+
endsClosed = false;
|
|
58
|
+
browserActiveAfterClose = true;
|
|
59
|
+
}
|
|
60
|
+
if (stepSucceeded && subcommand === "stop")
|
|
61
|
+
recordingClosedAfterBatch = true;
|
|
62
|
+
else if (stepSucceeded && browserActiveAfterClose && (subcommand === "start" || subcommand === "restart"))
|
|
63
|
+
recordingClosedAfterBatch = false;
|
|
64
|
+
}
|
|
65
|
+
else if (sawClose && browserLaunched !== false) {
|
|
66
|
+
endsClosed = false;
|
|
67
|
+
browserActiveAfterClose = true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return sawClose ? { endsClosed, recordingClosedAfterBatch, statePath } : undefined;
|
|
71
|
+
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Own upstream command-shape policies that decide whether the wrapper should allocate a managed browser session.
|
|
3
|
-
* Responsibilities: Keep local/sessionless command grammar out of the runtime execution planner while preserving exact upstream shapes.
|
|
4
|
-
* Scope: Pure argv-token policy; command discovery, subprocess execution, and presentation live in focused modules.
|
|
5
|
-
*/
|
|
6
1
|
import { hasOnlyBooleanFlags, hasOnlyOptionFlags, isNonFlagToken, stripSessionlessShapeGlobalFlags } from "./argv-grammar.js";
|
|
7
2
|
const SESSIONLESS_AUTH_SUBCOMMANDS = new Set(["save", "list", "show", "delete", "remove"]);
|
|
8
3
|
const PLUGIN_SESSIONLESS_SUBCOMMANDS = new Set(["list", "show", "add", "run"]);
|
|
@@ -101,5 +96,5 @@ function isSessionlessCommand(commandTokens) {
|
|
|
101
96
|
return false;
|
|
102
97
|
}
|
|
103
98
|
export function needsManagedSession(descriptor) {
|
|
104
|
-
return !isSessionlessCommand(descriptor.
|
|
99
|
+
return !isSessionlessCommand(descriptor.upstreamCommandTokens);
|
|
105
100
|
}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Centralize upstream agent-browser command capabilities that wrapper behavior depends on.
|
|
3
|
-
* Responsibilities: Normalize command aliases once and expose capability predicates for runtime planning,
|
|
4
|
-
* session/ref guards, result recommendations, and presentation summaries without coupling unrelated behaviors.
|
|
5
|
-
* Scope: Static command capability taxonomy only; command-shape parsing, spawning, and formatting live elsewhere.
|
|
6
|
-
*/
|
|
7
1
|
const ADDITIONAL_COMMAND_TOKENS = [
|
|
8
2
|
"a11y", "auth", "chat", "clipboard", "confirm", "connect", "dashboard", "deny", "device", "dialog", "diff", "doctor", "errors", "eval", "find", "frame", "get", "highlight", "inspect", "install", "is", "mcp", "plugin", "plugins", "profiles", "profiler", "react", "record", "removeinitscript", "session", "set", "skills", "snapshot", "state", "stream", "trace", "upgrade", "vitals", "wait", "web-vitals", "window",
|
|
9
3
|
];
|
|
@@ -67,6 +61,10 @@ const COMMAND_CAPABILITIES = [
|
|
|
67
61
|
invalidatesBatchRefs: true,
|
|
68
62
|
triggersPostMutationSnapshot: true,
|
|
69
63
|
},
|
|
64
|
+
{
|
|
65
|
+
command: "diff",
|
|
66
|
+
guardsPageRefs: true,
|
|
67
|
+
},
|
|
70
68
|
{
|
|
71
69
|
command: "download",
|
|
72
70
|
eligibleForPageChangeSummary: true,
|
|
@@ -98,6 +96,10 @@ const COMMAND_CAPABILITIES = [
|
|
|
98
96
|
command: "find",
|
|
99
97
|
eligibleForElectronHealthProbe: true,
|
|
100
98
|
},
|
|
99
|
+
{
|
|
100
|
+
command: "frame",
|
|
101
|
+
guardsPageRefs: true,
|
|
102
|
+
},
|
|
101
103
|
{
|
|
102
104
|
command: "focus",
|
|
103
105
|
guardsPageRefs: true,
|
|
@@ -110,6 +112,14 @@ const COMMAND_CAPABILITIES = [
|
|
|
110
112
|
navigationObservable: true,
|
|
111
113
|
triggersPostMutationSnapshot: true,
|
|
112
114
|
},
|
|
115
|
+
{
|
|
116
|
+
command: "get",
|
|
117
|
+
guardsPageRefs: true,
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
command: "highlight",
|
|
121
|
+
guardsPageRefs: true,
|
|
122
|
+
},
|
|
113
123
|
{
|
|
114
124
|
command: "hover",
|
|
115
125
|
eligibleForPageChangeSummary: true,
|
|
@@ -117,6 +127,10 @@ const COMMAND_CAPABILITIES = [
|
|
|
117
127
|
invalidatesBatchRefs: true,
|
|
118
128
|
triggersPostMutationSnapshot: true,
|
|
119
129
|
},
|
|
130
|
+
{
|
|
131
|
+
command: "is",
|
|
132
|
+
guardsPageRefs: true,
|
|
133
|
+
},
|
|
120
134
|
{
|
|
121
135
|
command: "keydown",
|
|
122
136
|
eligibleForElectronHealthProbe: true,
|
|
@@ -191,10 +205,12 @@ const COMMAND_CAPABILITIES = [
|
|
|
191
205
|
{
|
|
192
206
|
command: "screenshot",
|
|
193
207
|
eligibleForPageChangeSummary: true,
|
|
208
|
+
guardsPageRefs: true,
|
|
194
209
|
},
|
|
195
210
|
{
|
|
196
211
|
command: "scroll",
|
|
197
212
|
eligibleForPageChangeSummary: true,
|
|
213
|
+
guardsPageRefs: true,
|
|
198
214
|
invalidatesBatchRefs: true,
|
|
199
215
|
triggersPostMutationSnapshot: true,
|
|
200
216
|
},
|
|
@@ -287,6 +303,9 @@ export function normalizeCommandName(command) {
|
|
|
287
303
|
export function isCloseCommand(command) {
|
|
288
304
|
return hasCommandCapability(command, "closesSession");
|
|
289
305
|
}
|
|
306
|
+
export function isCloseAllCommand(commandTokens) {
|
|
307
|
+
return isCloseCommand(commandTokens[0]) && commandTokens.slice(1).includes("--all");
|
|
308
|
+
}
|
|
290
309
|
export function isOpenNavigationCommand(command) {
|
|
291
310
|
return hasCommandCapability(command, "openNavigation");
|
|
292
311
|
}
|
|
@@ -299,8 +318,16 @@ export function isSessionTabPinningExcludedCommand(command) {
|
|
|
299
318
|
export function isSessionTabPostCommandCorrectionExcludedCommand(command) {
|
|
300
319
|
return hasCommandCapability(command, "excludedFromPostCommandCorrection");
|
|
301
320
|
}
|
|
302
|
-
|
|
303
|
-
|
|
321
|
+
/** Upstream 0.33.2 record start swaps to a fresh active page before its already-active check, so even a failed start can replace the page; record restart navigates the current page only when a URL operand (any fourth token, mirroring upstream's positional slot) is present. */
|
|
322
|
+
export function isRecordPageTransitionCommand(tokens) {
|
|
323
|
+
if (tokens[0] !== "record")
|
|
324
|
+
return false;
|
|
325
|
+
if (tokens[1] === "start")
|
|
326
|
+
return true;
|
|
327
|
+
return tokens[1] === "restart" && tokens.length >= 4;
|
|
328
|
+
}
|
|
329
|
+
export function isRefInvalidatingBatchCommand(step) {
|
|
330
|
+
return hasCommandCapability(step[0], "invalidatesBatchRefs") || isRecordPageTransitionCommand(step);
|
|
304
331
|
}
|
|
305
332
|
export function isRefGuardedCommand(command) {
|
|
306
333
|
return hasCommandCapability(command, "guardsPageRefs");
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
/**
|
|
3
|
-
* Purpose: Canonical pi-agent-browser-native config policy shared by runtime and setup CLI.
|
|
4
|
-
* Responsibilities: Own config paths, provider descriptors, credential source parsing, layer validation/merge, status projection, and redacted summaries.
|
|
5
|
-
* Scope: Pure configuration policy plus synchronous status loading; secret command execution and browser/web-search runtime calls live elsewhere.
|
|
6
|
-
*/
|
|
7
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
8
3
|
import { homedir } from "node:os";
|
|
9
4
|
import { join, resolve } from "node:path";
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Load pi-agent-browser-native package configuration from Pi-scoped global, project, or explicit paths.
|
|
3
|
-
* Responsibilities: Resolve config layers, resolve secrets without exposing values, and provide redacted status for tools/CLIs.
|
|
4
|
-
* Scope: Package-owned configuration only; canonical config policy lives in config-policy.js, browser command execution and web-search API calls live in focused modules.
|
|
5
|
-
* Invariants/Assumptions: Credential sources from loaded config are passed through to the runtime; command credentials are resolved lazily at execution time and displayed values stay redacted.
|
|
6
|
-
*/
|
|
7
1
|
import { exec as execCallback } from "node:child_process";
|
|
8
2
|
import { readFile } from "node:fs/promises";
|
|
9
3
|
import { promisify } from "node:util";
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Parse and fetch Chrome DevTools Protocol metadata for wrapper-owned Electron launches.
|
|
3
|
-
* Responsibilities: Normalize CDP version/target JSON and perform bounded localhost CDP JSON fetches.
|
|
4
|
-
* Scope: Tiny Electron CDP boundary helpers only; launch, status, cleanup, and target selection stay in their owning modules.
|
|
5
|
-
* Usage: Imported by Electron launch and cleanup paths when polling `/json/version` and `/json/list`.
|
|
6
|
-
* Invariants/Assumptions: Malformed or unavailable CDP endpoints return undefined/empty metadata rather than throwing, matching prior caller behavior.
|
|
7
|
-
*/
|
|
8
1
|
import { isRecord } from "../parsing.js";
|
|
9
2
|
const ELECTRON_CDP_FETCH_TIMEOUT_MS = 1_000;
|
|
10
3
|
function asString(value) {
|
|
@@ -49,3 +42,9 @@ export async function fetchCdpJson(url, signal) {
|
|
|
49
42
|
clearTimeout(timeout);
|
|
50
43
|
}
|
|
51
44
|
}
|
|
45
|
+
export function boundElectronProbeString(value, maxLength = 240) {
|
|
46
|
+
const trimmed = value?.trim();
|
|
47
|
+
if (!trimmed)
|
|
48
|
+
return undefined;
|
|
49
|
+
return trimmed.length > maxLength ? `${trimmed.slice(0, Math.max(0, maxLength - 3))}...` : trimmed;
|
|
50
|
+
}
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Inspect and clean wrapper-owned Electron launch resources.
|
|
3
|
-
* Responsibilities: Report CDP liveness/targets without mutation and remove only tracked process/profile resources during explicit or shutdown cleanup.
|
|
4
|
-
* Scope: Host-side Electron status and resource cleanup only; upstream managed-session close remains in the extension entrypoint.
|
|
5
|
-
* Usage: Called by electron.status, electron.cleanup, and session_shutdown handling.
|
|
6
|
-
* Invariants/Assumptions: Cleanup operates only on launch records produced by this wrapper and prefers partial cleanup reporting over killing or deleting untracked resources.
|
|
7
|
-
*/
|
|
8
1
|
import { execFile } from "node:child_process";
|
|
9
2
|
import { rm } from "node:fs/promises";
|
|
10
3
|
import { promisify } from "node:util";
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Discover installed Electron desktop applications without invoking upstream agent-browser.
|
|
3
|
-
* Responsibilities: Scan bounded macOS app bundles and Linux .desktop launchers, apply Electron framework evidence gates, and return small platform-tagged app metadata.
|
|
4
|
-
* Scope: Discovery only; launch, cleanup, status, and CDP attachment live in later Electron lifecycle work items.
|
|
5
|
-
* Usage: Called by the agent_browser top-level electron.list shorthand and directly by tests through parameterized scan locations.
|
|
6
|
-
* Invariants/Assumptions: Discovery is best-effort, missing scan roots are ignored, malformed .desktop files are skipped, and results are capped before they reach model-visible output.
|
|
7
|
-
*/
|
|
8
1
|
import { constants as fsConstants } from "node:fs";
|
|
9
2
|
import { access, readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
10
3
|
import { homedir } from "node:os";
|
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Launch wrapper-owned Electron applications and discover their CDP endpoint.
|
|
3
|
-
* Responsibilities: Resolve Electron targets, enforce caller-owned allow/deny policy, create isolated userDataDir profiles, launch with remote debugging on an OS-chosen port, poll DevToolsActivePort, and read bounded CDP version/target metadata.
|
|
4
|
-
* Scope: Host-side Electron lifecycle setup only; upstream agent-browser attach/presentation stays in the extension entrypoint.
|
|
5
|
-
* Usage: Called by the agent_browser electron.launch shorthand before routing through upstream `connect`.
|
|
6
|
-
* Invariants/Assumptions: The wrapper only launches targets with Electron framework evidence, always uses an isolated temp profile, never accepts a caller-supplied remote debugging port, and cleans any spawned process/profile when cancellation interrupts readiness.
|
|
7
|
-
*/
|
|
8
1
|
import { spawn } from "node:child_process";
|
|
9
2
|
import { randomUUID } from "node:crypto";
|
|
10
3
|
import { readFile, rm } from "node:fs/promises";
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile top-level Electron wrapper inputs into validated Electron actions.
|
|
3
|
-
* Responsibilities: Enforce action-specific fields, launch-target rules, and wrapper-owned flag safety.
|
|
4
|
-
* Scope: Electron input-mode validation only; launch/probe/cleanup execution stays in the extension entrypoint.
|
|
5
|
-
*/
|
|
6
1
|
import { isRecord } from "../parsing.js";
|
|
7
2
|
import { AGENT_BROWSER_ELECTRON_ACTIONS, AGENT_BROWSER_ELECTRON_HANDOFFS, AGENT_BROWSER_ELECTRON_LIST_FIELDS, AGENT_BROWSER_ELECTRON_PROBE_FIELDS, AGENT_BROWSER_ELECTRON_RESERVED_APP_ARGS, AGENT_BROWSER_ELECTRON_TARGET_TYPES, } from "./types.js";
|
|
8
3
|
function validateOptionalNonEmptyString(input, fieldName) {
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile constrained job and lightweight QA wrapper inputs to upstream batch commands.
|
|
3
|
-
* Responsibilities: Validate job/QA fields, produce argv/stdin, and summarize QA diagnostic results.
|
|
4
|
-
* Scope: Job and QA modes only.
|
|
5
|
-
*/
|
|
6
1
|
import { isRecord } from "../parsing.js";
|
|
7
2
|
import { summarizeNetworkFailures } from "../results/network.js";
|
|
8
3
|
import { getBatchResultItems, getCommandNameFromBatchItem, getSelectValues } from "./shared.js";
|
|
@@ -271,7 +266,7 @@ export function buildQaCompactPassText(options) {
|
|
|
271
266
|
lines.push(`Page: ${pageParts.join(" — ")}`);
|
|
272
267
|
lines.push(`Checks run: ${describeQaChecksRun(options.checks)} (${options.batchStepCount} batch step${options.batchStepCount === 1 ? "" : "s"})`);
|
|
273
268
|
if (options.checks.diagnosticsResetAtStart && (options.checks.checkNetwork || options.checks.checkConsole || options.checks.checkErrors)) {
|
|
274
|
-
lines.push("Diagnostic
|
|
269
|
+
lines.push("Diagnostic isolation: URL QA clears enabled network/console buffers, then snapshots any page-error residue before opening the target. Only unchanged residue is ignored because upstream page-error clear is not reliable.");
|
|
275
270
|
}
|
|
276
271
|
if (options.checks.attached && !options.checks.diagnosticsResetAtStart && (options.checks.checkNetwork || options.checks.checkConsole || options.checks.checkErrors)) {
|
|
277
272
|
lines.push("Attached diagnostics: existing upstream session console/network/error buffers were preserved; rows may include events from before qa.attached started.");
|
|
@@ -285,6 +280,19 @@ export function buildQaCompactPassText(options) {
|
|
|
285
280
|
lines.push("Full diagnostic matrix: see details.qaPreset and details.batchSteps.");
|
|
286
281
|
return lines.join("\n");
|
|
287
282
|
}
|
|
283
|
+
export function buildQaCompactFailureText(options) {
|
|
284
|
+
const lines = [options.qaPreset.summary];
|
|
285
|
+
const pageParts = [options.page?.title, options.page?.url].filter((part) => typeof part === "string" && part.length > 0);
|
|
286
|
+
if (pageParts.length > 0)
|
|
287
|
+
lines.push(`Page: ${pageParts.join(" — ")}`);
|
|
288
|
+
if (options.qaPreset.failedChecks.length > 0)
|
|
289
|
+
lines.push("Failed checks:", ...options.qaPreset.failedChecks.map((failure) => `- ${failure}`));
|
|
290
|
+
if (options.qaPreset.warnings.length > 0)
|
|
291
|
+
lines.push("Warnings:", ...options.qaPreset.warnings.map((warning) => `- ${warning}`));
|
|
292
|
+
lines.push(`Checks run: ${describeQaChecksRun(options.checks)} (${options.batchStepCount} batch step${options.batchStepCount === 1 ? "" : "s"})`);
|
|
293
|
+
lines.push("Full diagnostic matrix: see details.qaPreset and details.batchSteps.");
|
|
294
|
+
return lines.join("\n");
|
|
295
|
+
}
|
|
288
296
|
const QA_VISIBLE_TEXT_TIMEOUT_MS = 5_000;
|
|
289
297
|
function formatQaExpectedTextPreview(text) {
|
|
290
298
|
return JSON.stringify(text.length > 80 ? `${text.slice(0, 77)}...` : text);
|
|
@@ -353,6 +361,34 @@ function extractQaTextAssertionResultText(item) {
|
|
|
353
361
|
}
|
|
354
362
|
return undefined;
|
|
355
363
|
}
|
|
364
|
+
function qaErrorSignature(error) {
|
|
365
|
+
if (typeof error === "string")
|
|
366
|
+
return error;
|
|
367
|
+
try {
|
|
368
|
+
return JSON.stringify(error);
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
return String(error);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
function subtractQaBaselineErrors(errors, baselineErrors) {
|
|
375
|
+
const baselineCounts = new Map();
|
|
376
|
+
for (const error of baselineErrors) {
|
|
377
|
+
const signature = qaErrorSignature(error);
|
|
378
|
+
baselineCounts.set(signature, (baselineCounts.get(signature) ?? 0) + 1);
|
|
379
|
+
}
|
|
380
|
+
let ignoredCount = 0;
|
|
381
|
+
const novelErrors = errors.filter((error) => {
|
|
382
|
+
const signature = qaErrorSignature(error);
|
|
383
|
+
const count = baselineCounts.get(signature) ?? 0;
|
|
384
|
+
if (count === 0)
|
|
385
|
+
return true;
|
|
386
|
+
baselineCounts.set(signature, count - 1);
|
|
387
|
+
ignoredCount += 1;
|
|
388
|
+
return false;
|
|
389
|
+
});
|
|
390
|
+
return { ignoredCount, novelErrors };
|
|
391
|
+
}
|
|
356
392
|
function isDiagnosticResetCommand(item) {
|
|
357
393
|
const command = item.command;
|
|
358
394
|
if (!Array.isArray(command) || !command.every((token) => typeof token === "string"))
|
|
@@ -377,17 +413,29 @@ export function analyzeQaPresetResults(data, compiled) {
|
|
|
377
413
|
return undefined;
|
|
378
414
|
const failedChecks = [];
|
|
379
415
|
const warnings = [];
|
|
380
|
-
|
|
416
|
+
const baselineErrorIndex = compiled?.checks.diagnosticsResetAtStart && compiled.checks.checkErrors
|
|
417
|
+
? compiled.steps.findIndex((step) => step.generatedFrom === "qa.errorBaselineAfterClear")
|
|
418
|
+
: -1;
|
|
419
|
+
const baselineErrorItem = baselineErrorIndex >= 0 ? items[baselineErrorIndex] : undefined;
|
|
420
|
+
const baselineErrorResult = isRecord(baselineErrorItem?.result) ? baselineErrorItem.result : undefined;
|
|
421
|
+
const baselineErrors = Array.isArray(baselineErrorResult?.errors) ? baselineErrorResult.errors : [];
|
|
422
|
+
for (const [index, item] of items.entries()) {
|
|
381
423
|
if (item.success === false) {
|
|
382
424
|
failedChecks.push(`${getCommandNameFromBatchItem(item) ?? "step"} failed`);
|
|
383
425
|
}
|
|
426
|
+
if (index === baselineErrorIndex)
|
|
427
|
+
continue;
|
|
384
428
|
const result = isRecord(item.result) ? item.result : undefined;
|
|
385
429
|
const commandName = getCommandNameFromBatchItem(item);
|
|
386
430
|
if (compiled?.checks.diagnosticsResetAtStart && isDiagnosticResetCommand(item)) {
|
|
387
431
|
continue;
|
|
388
432
|
}
|
|
389
433
|
if (commandName === "errors" && Array.isArray(result?.errors) && result.errors.length > 0) {
|
|
390
|
-
|
|
434
|
+
const { ignoredCount, novelErrors } = subtractQaBaselineErrors(result.errors, baselineErrors);
|
|
435
|
+
if (novelErrors.length > 0)
|
|
436
|
+
failedChecks.push(`${novelErrors.length} page error(s)`);
|
|
437
|
+
if (ignoredCount > 0)
|
|
438
|
+
warnings.push(`${ignoredCount} post-clear page error residue row(s) ignored as unchanged`);
|
|
391
439
|
}
|
|
392
440
|
if (commandName === "console" && Array.isArray(result?.messages)) {
|
|
393
441
|
const errorCount = result.messages.filter((message) => isRecord(message) && /error/i.test(String(message.type ?? message.level ?? ""))).length;
|
|
@@ -482,11 +530,15 @@ export function compileAgentBrowserQaPreset(input) {
|
|
|
482
530
|
steps.push({ action: "wait", args: ["network", "requests", "--clear"] });
|
|
483
531
|
if (diagnosticsResetAtStart && checkConsole)
|
|
484
532
|
steps.push({ action: "wait", args: ["console", "--clear"] });
|
|
485
|
-
if (diagnosticsResetAtStart && checkErrors)
|
|
533
|
+
if (diagnosticsResetAtStart && checkErrors) {
|
|
486
534
|
steps.push({ action: "wait", args: ["errors", "--clear"] });
|
|
535
|
+
steps.push({ action: "wait", args: ["errors"], generatedFrom: "qa.errorBaselineAfterClear" });
|
|
536
|
+
}
|
|
487
537
|
if (!attached && normalizedUrl)
|
|
488
538
|
steps.push({ action: "open", args: ["open", normalizedUrl] });
|
|
489
539
|
steps.push({ action: "wait", args: ["wait", "--load", loadState] });
|
|
540
|
+
if (checkConsole || checkErrors)
|
|
541
|
+
steps.push({ action: "wait", args: ["wait", "150"], generatedFrom: "qa.diagnosticSettle" });
|
|
490
542
|
for (const text of expectedText) {
|
|
491
543
|
steps.push({ action: "assertText", args: ["wait", "--fn", buildQaVisibleTextPredicate(text), "--timeout", String(QA_VISIBLE_TEXT_TIMEOUT_MS)] });
|
|
492
544
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Purpose: Compile and analyze experimental DOM/source and network source lookup input modes.
|
|
3
|
-
* Responsibilities: Build lookup batches, collect DOM/React/workspace candidates, and redact network lookup surfaces.
|
|
4
|
-
* Scope: Source lookup and network source lookup only.
|
|
5
|
-
*/
|
|
6
1
|
import { readFile, readdir } from "node:fs/promises";
|
|
7
2
|
import { extname, join } from "node:path";
|
|
8
3
|
import { isRecord } from "../parsing.js";
|
|
@@ -266,8 +261,8 @@ export function compileAgentBrowserNetworkSourceLookup(input) {
|
|
|
266
261
|
return { error: "networkSourceLookup.filter must be a non-empty string when provided." };
|
|
267
262
|
if (requestId !== undefined && (typeof requestId !== "string" || requestId.trim().length === 0))
|
|
268
263
|
return { error: "networkSourceLookup.requestId must be a non-empty string when provided." };
|
|
269
|
-
if (namespace !== undefined && (typeof namespace !== "string" || namespace.trim().length === 0))
|
|
270
|
-
return { error: "networkSourceLookup.namespace must be a non-empty string when provided." };
|
|
264
|
+
if (namespace !== undefined && (typeof namespace !== "string" || (namespace !== "" && namespace.trim().length === 0)))
|
|
265
|
+
return { error: "networkSourceLookup.namespace must be a non-empty string or the empty default namespace when provided." };
|
|
271
266
|
if (session !== undefined && (typeof session !== "string" || session.trim().length === 0))
|
|
272
267
|
return { error: "networkSourceLookup.session must be a non-empty string when provided." };
|
|
273
268
|
if (url !== undefined && (typeof url !== "string" || url.trim().length === 0))
|