pi-agent-browser-native 0.9.6 → 0.9.7
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 +95 -1
- package/README.md +14 -6
- package/dist/extensions/agent-browser/index.js +1276 -350
- package/dist/packaged/lib/browser-session-conversion.js +157 -21
- package/dist/packaged/lib/playbook.js +42 -8
- package/dist/packaged/lib/results/snapshot.js +140 -11
- package/dist/packaged/lib/runtime.js +58 -10
- package/docs/ARCHITECTURE.md +19 -10
- package/docs/CODE_QUALITY.md +21 -5
- package/docs/COMMAND_REFERENCE.md +154 -38
- package/docs/ELECTRON.md +1 -1
- package/docs/PERFORMANCE.md +12 -3
- package/docs/REFERENCE.md +14 -14
- package/docs/RELEASE.md +41 -18
- package/docs/REQUIREMENTS.md +6 -0
- package/docs/SESSION_STORAGE.md +3 -3
- package/docs/SUPPORT_MATRIX.md +25 -23
- package/docs/TOOL_CONTRACT.md +37 -14
- package/docs/platform-smoke.md +18 -14
- package/package.json +6 -3
- package/platform-smoke.config.mjs +3 -2
- package/scripts/agent-browser-capability-baseline.mjs +16 -2
- package/scripts/agent-browser-target.mjs +1 -1
- package/scripts/capability-options.mjs +20 -0
- package/scripts/capability-samples.mjs +23 -10
- package/scripts/platform-smoke/commands.mjs +30 -4
- package/scripts/platform-smoke/doctor-support.mjs +11 -2
- package/scripts/platform-smoke/doctor-windows.mjs +1 -1
- package/scripts/platform-smoke/doctor.mjs +26 -11
- package/scripts/platform-smoke/linux-image/Dockerfile +6 -3
- package/scripts/platform-smoke/platform-build-windows.ps1 +23 -3
- package/scripts/platform-smoke/suite-checks.mjs +11 -1
- package/scripts/platform-smoke/targets.mjs +4 -3
- package/scripts/platform-smoke.mjs +68 -25
|
@@ -855,6 +855,7 @@ var init_argv_grammar = __esm({
|
|
|
855
855
|
"-q",
|
|
856
856
|
"--verbose",
|
|
857
857
|
"-v",
|
|
858
|
+
"--use-system-ca",
|
|
858
859
|
"--webgpu"
|
|
859
860
|
]);
|
|
860
861
|
}
|
|
@@ -1150,6 +1151,9 @@ var init_text = __esm({
|
|
|
1150
1151
|
});
|
|
1151
1152
|
|
|
1152
1153
|
// dist/extensions/agent-browser/lib/orchestration/batch-stdin.js
|
|
1154
|
+
function isNativeBatchOption(token) {
|
|
1155
|
+
return token === "--bail" || token === "--omit-command";
|
|
1156
|
+
}
|
|
1153
1157
|
function normalizeUrlLessOpen(args, stdin, batchStep = false) {
|
|
1154
1158
|
const { tokens, indices } = batchStep ? { tokens: args, indices: args.map((_, index) => index) } : projectUpstreamGlobalFlags(args);
|
|
1155
1159
|
if (tokens[0] === "open" && !tokens.slice(1).some((token) => !token.startsWith("--"))) {
|
|
@@ -1159,7 +1163,7 @@ function normalizeUrlLessOpen(args, stdin, batchStep = false) {
|
|
|
1159
1163
|
if (tokens[0] !== "batch") {
|
|
1160
1164
|
return { args, stdin };
|
|
1161
1165
|
}
|
|
1162
|
-
if (tokens.slice(1).some((token) => token
|
|
1166
|
+
if (tokens.slice(1).some((token) => !isNativeBatchOption(token))) {
|
|
1163
1167
|
return { args: normalizeRawBatchRows(args, tokens, indices), stdin };
|
|
1164
1168
|
}
|
|
1165
1169
|
const steps = parseUserBatchStdin(stdin).steps;
|
|
@@ -1175,7 +1179,7 @@ function normalizeUrlLessOpen(args, stdin, batchStep = false) {
|
|
|
1175
1179
|
function normalizeRawBatchRows(args, tokens, indices) {
|
|
1176
1180
|
let normalized;
|
|
1177
1181
|
for (const [offset, token] of tokens.slice(1).entries()) {
|
|
1178
|
-
if (token
|
|
1182
|
+
if (isNativeBatchOption(token)) {
|
|
1179
1183
|
continue;
|
|
1180
1184
|
}
|
|
1181
1185
|
const step = parseBatchCommandArgument(token).step;
|
|
@@ -1251,20 +1255,37 @@ function parseUserBatchStdin(stdin) {
|
|
|
1251
1255
|
return { steps };
|
|
1252
1256
|
}
|
|
1253
1257
|
function getUpstreamEffectiveBatchSteps(commandTokens, stdin) {
|
|
1258
|
+
return getUpstreamBatchInputSteps(commandTokens, stdin).filter((step) => step.length > 0);
|
|
1259
|
+
}
|
|
1260
|
+
function getUpstreamBatchInputSteps(commandTokens, stdin) {
|
|
1254
1261
|
if (commandTokens[0] !== "batch") {
|
|
1255
1262
|
return [];
|
|
1256
1263
|
}
|
|
1257
1264
|
const argumentSteps = commandTokens.slice(1).flatMap((command) => {
|
|
1258
|
-
if (command
|
|
1265
|
+
if (isNativeBatchOption(command)) {
|
|
1259
1266
|
return [];
|
|
1260
1267
|
}
|
|
1261
1268
|
const step = parseBatchCommandArgument(command).step;
|
|
1262
1269
|
return step ? [step] : [];
|
|
1263
1270
|
});
|
|
1264
|
-
if (commandTokens.slice(1).some((token) => token
|
|
1271
|
+
if (commandTokens.slice(1).some((token) => !isNativeBatchOption(token))) {
|
|
1265
1272
|
return argumentSteps;
|
|
1266
1273
|
}
|
|
1267
|
-
return parseUserBatchStdin(stdin).steps
|
|
1274
|
+
return parseUserBatchStdin(stdin).steps ?? [];
|
|
1275
|
+
}
|
|
1276
|
+
function resolveIndexedBatchCommands(envelope, commandTokens, stdin) {
|
|
1277
|
+
if (commandTokens[0] !== "batch" || !commandTokens.slice(1).includes("--omit-command") || !Array.isArray(envelope?.data) || !envelope.data.some((row) => isRecord(row) && row.command === void 0 && row.index !== void 0)) {
|
|
1278
|
+
return envelope;
|
|
1279
|
+
}
|
|
1280
|
+
const steps = getUpstreamBatchInputSteps(commandTokens, stdin);
|
|
1281
|
+
const data = envelope.data.map((row) => {
|
|
1282
|
+
if (!isRecord(row) || row.command !== void 0 || typeof row.index !== "number" || !Number.isSafeInteger(row.index) || row.index < 0) {
|
|
1283
|
+
return row;
|
|
1284
|
+
}
|
|
1285
|
+
const command = steps.at(row.index);
|
|
1286
|
+
return command !== void 0 && command.length > 0 ? { ...row, command } : row;
|
|
1287
|
+
});
|
|
1288
|
+
return { ...envelope, data };
|
|
1268
1289
|
}
|
|
1269
1290
|
var BATCH_STDIN_EXAMPLE, BatchWords;
|
|
1270
1291
|
var init_batch_stdin = __esm({
|
|
@@ -1272,6 +1293,7 @@ var init_batch_stdin = __esm({
|
|
|
1272
1293
|
"use strict";
|
|
1273
1294
|
init_argv_grammar();
|
|
1274
1295
|
init_shared();
|
|
1296
|
+
init_parsing();
|
|
1275
1297
|
init_text();
|
|
1276
1298
|
BATCH_STDIN_EXAMPLE = ' Example: { "args": ["batch"], "stdin": "[[\\"get\\",\\"title\\"],[\\"get\\",\\"url\\"]]" }';
|
|
1277
1299
|
BatchWords = class {
|
|
@@ -1711,7 +1733,7 @@ function redactBatchRows(args) {
|
|
|
1711
1733
|
return replacements;
|
|
1712
1734
|
}
|
|
1713
1735
|
for (let index = 1; index < batch.tokens.length; index++) {
|
|
1714
|
-
if (batch.tokens[index]
|
|
1736
|
+
if (isNativeBatchOption(batch.tokens[index])) {
|
|
1715
1737
|
continue;
|
|
1716
1738
|
}
|
|
1717
1739
|
const step = parseBatchCommandArgument(batch.tokens[index]).step;
|
|
@@ -3895,15 +3917,30 @@ function snapshotDefinition(snapshot) {
|
|
|
3895
3917
|
function snapshotMetadataValid(definition) {
|
|
3896
3918
|
return (definition.target === void 0 || decodeBrowserTarget(definition.target) !== void 0) && (definition.generation === void 0 || typeof definition.generation === "string");
|
|
3897
3919
|
}
|
|
3898
|
-
function
|
|
3899
|
-
|
|
3920
|
+
function snapshotReferencesValid(refs) {
|
|
3921
|
+
return Object.keys(refs).every((id) => SNAPSHOT_REF_ID.test(id) && isBrowserSnapshotReference(refs[id]));
|
|
3922
|
+
}
|
|
3923
|
+
function assertSnapshotDefinition(definition) {
|
|
3924
|
+
if (!isRecord(definition) || typeof definition.id !== "string" || definition.id.length === 0 || !isRecord(definition.refs) || !snapshotMetadataValid(definition) || !snapshotReferencesValid(definition.refs)) {
|
|
3900
3925
|
throw new Error("Missing or invalid browser snapshot definition; take a new complete snapshot before using refs.");
|
|
3901
3926
|
}
|
|
3902
|
-
|
|
3927
|
+
}
|
|
3928
|
+
function snapshotFromDefinition(definition) {
|
|
3929
|
+
assertSnapshotDefinition(definition);
|
|
3930
|
+
const refIds = Object.keys(definition.refs);
|
|
3931
|
+
const refs = {};
|
|
3932
|
+
let named = false;
|
|
3933
|
+
for (const id of refIds) {
|
|
3934
|
+
const ref = definition.refs[id];
|
|
3935
|
+
if (isNamedBrowserSnapshotReference(ref)) {
|
|
3936
|
+
refs[id] = ref;
|
|
3937
|
+
named = true;
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3903
3940
|
return {
|
|
3904
3941
|
snapshotId: definition.id,
|
|
3905
|
-
refIds
|
|
3906
|
-
...
|
|
3942
|
+
refIds,
|
|
3943
|
+
...named ? { refs } : {},
|
|
3907
3944
|
target: definition.target === void 0 ? void 0 : decodeBrowserTarget(definition.target),
|
|
3908
3945
|
generation: typeof definition.generation === "string" ? definition.generation : void 0
|
|
3909
3946
|
};
|
|
@@ -4005,7 +4042,7 @@ function applyArtifactChanges(previous, changes) {
|
|
|
4005
4042
|
function appendBrowserTransition(pi, record) {
|
|
4006
4043
|
pi.appendEntry(BROWSER_TRANSITION_ENTRY, record);
|
|
4007
4044
|
}
|
|
4008
|
-
var BROWSER_EVENT_VERSION;
|
|
4045
|
+
var BROWSER_EVENT_VERSION, SNAPSHOT_REF_ID;
|
|
4009
4046
|
var init_browser_transcript = __esm({
|
|
4010
4047
|
"dist/extensions/agent-browser/lib/browser-transcript.js"() {
|
|
4011
4048
|
"use strict";
|
|
@@ -4018,6 +4055,7 @@ var init_browser_transcript = __esm({
|
|
|
4018
4055
|
init_browser_transcript_contracts();
|
|
4019
4056
|
init_browser_transcript_validation();
|
|
4020
4057
|
BROWSER_EVENT_VERSION = 1;
|
|
4058
|
+
SNAPSHOT_REF_ID = /^e\d+$/;
|
|
4021
4059
|
}
|
|
4022
4060
|
});
|
|
4023
4061
|
|
|
@@ -4548,7 +4586,10 @@ function hasLaunchScopedFlagToken(args, flag) {
|
|
|
4548
4586
|
const commandStartIndex = findCommandStartIndex(args);
|
|
4549
4587
|
return commandStartIndex === void 0 || args[commandStartIndex] !== "wait" || args.indexOf(flag) < commandStartIndex;
|
|
4550
4588
|
}
|
|
4551
|
-
|
|
4589
|
+
function hasBrowserLaunchFlag(args) {
|
|
4590
|
+
return BROWSER_LAUNCH_FLAGS.some((flag) => hasLaunchScopedFlagToken(args, flag));
|
|
4591
|
+
}
|
|
4592
|
+
var LAUNCH_SCOPED_FLAG_DEFINITIONS, LAUNCH_SCOPED_FLAGS, LAUNCH_SCOPED_FLAG_LABEL, OPEN_RESULT_TAB_CORRECTION_FLAGS, MANAGED_RESTORE_INCOMPATIBLE_FLAGS, MANAGED_RESTORE_INCOMPATIBLE_ENVS, MANAGED_RESTORE_INCOMPATIBLE_BOOLEAN_ENVS, HELPER_INHERITED_LAUNCH_FLAGS, BROWSER_LAUNCH_FLAGS;
|
|
4552
4593
|
var init_launch_scoped_flags = __esm({
|
|
4553
4594
|
"dist/extensions/agent-browser/lib/launch-scoped-flags.js"() {
|
|
4554
4595
|
"use strict";
|
|
@@ -4739,6 +4780,10 @@ var init_launch_scoped_flags = __esm({
|
|
|
4739
4780
|
"AGENT_BROWSER_ALLOW_FILE_ACCESS",
|
|
4740
4781
|
"AGENT_BROWSER_WEBGPU"
|
|
4741
4782
|
];
|
|
4783
|
+
HELPER_INHERITED_LAUNCH_FLAGS = /* @__PURE__ */ new Set(["--namespace", "--idle-timeout"]);
|
|
4784
|
+
BROWSER_LAUNCH_FLAGS = [
|
|
4785
|
+
.../* @__PURE__ */ new Set([...LAUNCH_SCOPED_FLAGS, ...MANAGED_RESTORE_INCOMPATIBLE_FLAGS])
|
|
4786
|
+
].filter((flag) => !HELPER_INHERITED_LAUNCH_FLAGS.has(flag));
|
|
4742
4787
|
}
|
|
4743
4788
|
});
|
|
4744
4789
|
|
|
@@ -4756,14 +4801,86 @@ var init_temp_mutation_queue = __esm({
|
|
|
4756
4801
|
}
|
|
4757
4802
|
});
|
|
4758
4803
|
|
|
4804
|
+
// dist/extensions/agent-browser/lib/browser-execution-policy-debug.js
|
|
4805
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4806
|
+
import { debuglog } from "node:util";
|
|
4807
|
+
function debugPolicyFailure(stage, reason, error) {
|
|
4808
|
+
if (!policyDebugEnabled) {
|
|
4809
|
+
return;
|
|
4810
|
+
}
|
|
4811
|
+
const context2 = attempts?.getStore();
|
|
4812
|
+
const code = nativeField(error, "code");
|
|
4813
|
+
const syscall = nativeField(error, "syscall");
|
|
4814
|
+
const exit = isRecord(error) && typeof error.code === "number" && Number.isSafeInteger(error.code) ? error.code : "-";
|
|
4815
|
+
debug("attempt=%s phase=%s stage=%s reason=%s code=%s syscall=%s exit=%s", context2?.attempt ?? 0, context2?.phase ?? "standalone", stage, reason, code, syscall, exit);
|
|
4816
|
+
}
|
|
4817
|
+
function nativeField(error, field) {
|
|
4818
|
+
const value = isRecord(error) ? error[field] : void 0;
|
|
4819
|
+
if (typeof value !== "string") {
|
|
4820
|
+
return "-";
|
|
4821
|
+
}
|
|
4822
|
+
if (field === "code") {
|
|
4823
|
+
return /^(?:E[A-Z0-9]{1,24}|ABORT_ERR|ERR_[A-Z_]{1,48})$/.test(value) ? value : "unknown";
|
|
4824
|
+
}
|
|
4825
|
+
if (value.startsWith("spawn ")) {
|
|
4826
|
+
return "spawn";
|
|
4827
|
+
}
|
|
4828
|
+
return syscalls.has(value) ? value : "unknown";
|
|
4829
|
+
}
|
|
4830
|
+
function withPolicyDebugAttempt(run) {
|
|
4831
|
+
return attempts === void 0 ? run() : attempts.run({ attempt: ++nextAttempt, phase: "acquire" }, run);
|
|
4832
|
+
}
|
|
4833
|
+
function policyDebugPhase(phase, run) {
|
|
4834
|
+
const context2 = attempts?.getStore();
|
|
4835
|
+
return context2 === void 0 || attempts === void 0 ? run : () => attempts.run({ ...context2, phase }, run);
|
|
4836
|
+
}
|
|
4837
|
+
function policyDebugError(error) {
|
|
4838
|
+
const code = nativeField(error, "code");
|
|
4839
|
+
const syscall = nativeField(error, "syscall");
|
|
4840
|
+
let normalizedCode = code === "-" ? void 0 : code;
|
|
4841
|
+
if (isRecord(error) && typeof error.code === "number" && Number.isSafeInteger(error.code)) {
|
|
4842
|
+
normalizedCode = error.code;
|
|
4843
|
+
}
|
|
4844
|
+
return { code: normalizedCode, syscall: syscall === "-" ? void 0 : syscall };
|
|
4845
|
+
}
|
|
4846
|
+
var debug, policyDebugEnabled, attempts, nextAttempt, syscalls;
|
|
4847
|
+
var init_browser_execution_policy_debug = __esm({
|
|
4848
|
+
"dist/extensions/agent-browser/lib/browser-execution-policy-debug.js"() {
|
|
4849
|
+
"use strict";
|
|
4850
|
+
init_parsing();
|
|
4851
|
+
debug = debuglog("pi-agent-browser-policy");
|
|
4852
|
+
policyDebugEnabled = debug.enabled;
|
|
4853
|
+
attempts = policyDebugEnabled ? new AsyncLocalStorage() : void 0;
|
|
4854
|
+
nextAttempt = 0;
|
|
4855
|
+
syscalls = /* @__PURE__ */ new Set([
|
|
4856
|
+
"mkdir",
|
|
4857
|
+
"lstat",
|
|
4858
|
+
"stat",
|
|
4859
|
+
"scandir",
|
|
4860
|
+
"open",
|
|
4861
|
+
"read",
|
|
4862
|
+
"write",
|
|
4863
|
+
"rename",
|
|
4864
|
+
"rmdir",
|
|
4865
|
+
"unlink",
|
|
4866
|
+
"rm",
|
|
4867
|
+
"kill",
|
|
4868
|
+
"spawn",
|
|
4869
|
+
"connect",
|
|
4870
|
+
"listen"
|
|
4871
|
+
]);
|
|
4872
|
+
}
|
|
4873
|
+
});
|
|
4874
|
+
|
|
4759
4875
|
// dist/extensions/agent-browser/lib/process-identity.js
|
|
4760
4876
|
import { execFile } from "node:child_process";
|
|
4877
|
+
import { readFile } from "node:fs/promises";
|
|
4761
4878
|
import { dirname, join, win32 } from "node:path";
|
|
4762
4879
|
function getCurrentProcessUid() {
|
|
4763
4880
|
return typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
4764
4881
|
}
|
|
4765
4882
|
function buildProcessStartIdentityCommand(pid, platform = process.platform) {
|
|
4766
|
-
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
4883
|
+
if (!Number.isSafeInteger(pid) || pid <= 0 || platform === "linux") {
|
|
4767
4884
|
return void 0;
|
|
4768
4885
|
}
|
|
4769
4886
|
const configuredSystemRoot = process.env.SystemRoot;
|
|
@@ -4773,11 +4890,12 @@ function buildProcessStartIdentityCommand(pid, platform = process.platform) {
|
|
|
4773
4890
|
"-NoProfile",
|
|
4774
4891
|
"-NonInteractive",
|
|
4775
4892
|
"-Command",
|
|
4776
|
-
`$p =
|
|
4893
|
+
`$ErrorActionPreference = 'Stop'; $p = $null; try { $p = [System.Diagnostics.Process]::GetProcessById(${pid}); [long]$ticks = $p.StartTime.ToUniversalTime().Ticks; if ($ticks -le 0) { throw 'Process start ticks unavailable' }; [Console]::Out.WriteLine("${WINDOWS_PROCESS_START_IDENTITY_PREFIX}" + $ticks.ToString([Globalization.CultureInfo]::InvariantCulture)) } finally { if ($null -ne $p) { $p.Dispose() } }`
|
|
4777
4894
|
],
|
|
4778
4895
|
file: win32.join(windowsSystemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
|
4779
4896
|
} : {
|
|
4780
4897
|
args: ["-p", String(pid), "-o", "lstart="],
|
|
4898
|
+
env: { ...process.env, TZ: "UTC0", LC_ALL: "C" },
|
|
4781
4899
|
file: platform === "android" ? join(dirname(process.execPath), "ps") : "/bin/ps"
|
|
4782
4900
|
};
|
|
4783
4901
|
}
|
|
@@ -4804,14 +4922,22 @@ function normalizeProcessStartIdentity(stdout) {
|
|
|
4804
4922
|
}
|
|
4805
4923
|
return trimmed.replace(/\s+/g, " ");
|
|
4806
4924
|
}
|
|
4925
|
+
function debugIdentityBudget(budget) {
|
|
4926
|
+
debugPolicyFailure("probe.budget", budget?.signal?.aborted === true ? "cancelled" : "deadline");
|
|
4927
|
+
}
|
|
4807
4928
|
async function executeProcessStartIdentityCommand(command, budget = {}) {
|
|
4808
|
-
if (budget.signal?.aborted === true || budget.deadline !== void 0 &&
|
|
4929
|
+
if (budget.signal?.aborted === true || budget.deadline !== void 0 && performance.now() >= budget.deadline) {
|
|
4930
|
+
debugIdentityBudget(budget);
|
|
4809
4931
|
return void 0;
|
|
4810
4932
|
}
|
|
4811
|
-
const timeout = Math.max(1, Math.min(PROCESS_START_IDENTITY_TIMEOUT_MS, (budget.deadline ?? Infinity) -
|
|
4933
|
+
const timeout = Math.max(1, Math.ceil(Math.min(PROCESS_START_IDENTITY_TIMEOUT_MS, (budget.deadline ?? Infinity) - performance.now())));
|
|
4812
4934
|
return await new Promise((resolve19) => {
|
|
4813
|
-
execFile(command.file, command.args, { timeout, signal: budget.signal }, (error, stdout) => {
|
|
4814
|
-
|
|
4935
|
+
execFile(command.file, command.args, { env: command.env, timeout, signal: budget.signal }, (error, stdout) => {
|
|
4936
|
+
const identity = error ? void 0 : normalizeProcessStartIdentity(stdout);
|
|
4937
|
+
if (identity === void 0) {
|
|
4938
|
+
debugPolicyFailure("probe.execute", error ? "native-error" : "invalid-output", error);
|
|
4939
|
+
}
|
|
4940
|
+
resolve19(identity);
|
|
4815
4941
|
});
|
|
4816
4942
|
});
|
|
4817
4943
|
}
|
|
@@ -4824,14 +4950,67 @@ async function resolveProcessStartIdentityFromCommands(commands, execute = execu
|
|
|
4824
4950
|
}
|
|
4825
4951
|
return void 0;
|
|
4826
4952
|
}
|
|
4953
|
+
async function readLinuxProcfsText(path, budget) {
|
|
4954
|
+
if (identityBudgetExpired(budget)) {
|
|
4955
|
+
debugIdentityBudget(budget);
|
|
4956
|
+
return void 0;
|
|
4957
|
+
}
|
|
4958
|
+
try {
|
|
4959
|
+
return await readFile(path, { encoding: "latin1", signal: budget.signal });
|
|
4960
|
+
} catch (error) {
|
|
4961
|
+
debugPolicyFailure("probe.read", "native-error", error);
|
|
4962
|
+
return void 0;
|
|
4963
|
+
}
|
|
4964
|
+
}
|
|
4965
|
+
async function readLinuxBootId(budget) {
|
|
4966
|
+
const bootId = (await readLinuxProcfsText(LINUX_BOOT_ID_PATH, budget))?.replace(/\n$/, "");
|
|
4967
|
+
if (bootId === void 0 || !LINUX_BOOT_ID_PATTERN.test(bootId)) {
|
|
4968
|
+
debugPolicyFailure("probe.boot-id", bootId === void 0 ? "unavailable" : "invalid-output");
|
|
4969
|
+
return void 0;
|
|
4970
|
+
}
|
|
4971
|
+
return bootId;
|
|
4972
|
+
}
|
|
4973
|
+
function parseLinuxStartTicks(stat16, pid) {
|
|
4974
|
+
const header = `${String(pid)} (`;
|
|
4975
|
+
const commEnd = stat16.lastIndexOf(")");
|
|
4976
|
+
if (!stat16.startsWith(header) || commEnd < header.length || stat16[commEnd + 1] !== " ") {
|
|
4977
|
+
return void 0;
|
|
4978
|
+
}
|
|
4979
|
+
const ticks = stat16.slice(commEnd + 2).replace(/\n$/, "").split(" ").at(LINUX_STAT_START_TICKS_INDEX);
|
|
4980
|
+
return ticks !== void 0 && /^[0-9]+$/.test(ticks) ? ticks : void 0;
|
|
4981
|
+
}
|
|
4982
|
+
async function readLinuxProcessStartIdentity(pid, budget = {}) {
|
|
4983
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) {
|
|
4984
|
+
return void 0;
|
|
4985
|
+
}
|
|
4986
|
+
const bootId = await readLinuxBootId(budget);
|
|
4987
|
+
if (bootId === void 0) {
|
|
4988
|
+
return void 0;
|
|
4989
|
+
}
|
|
4990
|
+
const stat16 = await readLinuxProcfsText(`/proc/${String(pid)}/stat`, budget);
|
|
4991
|
+
if (stat16 === void 0) {
|
|
4992
|
+
return void 0;
|
|
4993
|
+
}
|
|
4994
|
+
const ticks = parseLinuxStartTicks(stat16, pid);
|
|
4995
|
+
if (ticks === void 0) {
|
|
4996
|
+
debugPolicyFailure("probe.stat", "invalid-output");
|
|
4997
|
+
return void 0;
|
|
4998
|
+
}
|
|
4999
|
+
return `${LINUX_PROCESS_START_IDENTITY_PREFIX}${bootId}:${ticks}`;
|
|
5000
|
+
}
|
|
4827
5001
|
async function readUncachedProcessStartIdentity(pid, platform, budget) {
|
|
4828
|
-
|
|
5002
|
+
if (platform === "linux") {
|
|
5003
|
+
return await readLinuxProcessStartIdentity(pid, budget);
|
|
5004
|
+
}
|
|
5005
|
+
const identity = await resolveProcessStartIdentityFromCommands(buildProcessStartIdentityCommands(pid, platform), (command) => executeProcessStartIdentityCommand(command, budget));
|
|
5006
|
+
return identity === void 0 || platform === "win32" ? identity : `${POSIX_PROCESS_START_IDENTITY_PREFIX}${identity}`;
|
|
4829
5007
|
}
|
|
4830
5008
|
function identityBudgetExpired(budget) {
|
|
4831
|
-
return budget?.signal?.aborted === true || budget?.deadline !== void 0 &&
|
|
5009
|
+
return budget?.signal?.aborted === true || budget?.deadline !== void 0 && performance.now() >= budget.deadline;
|
|
4832
5010
|
}
|
|
4833
5011
|
async function readProcessStartIdentity(pid, platform = process.platform, budget) {
|
|
4834
5012
|
if (identityBudgetExpired(budget)) {
|
|
5013
|
+
debugIdentityBudget(budget);
|
|
4835
5014
|
return void 0;
|
|
4836
5015
|
}
|
|
4837
5016
|
if (pid !== process.pid || platform !== process.platform) {
|
|
@@ -4861,20 +5040,35 @@ async function readCachedProcessStartIdentity(pid, platform) {
|
|
|
4861
5040
|
return await currentProcessStartIdentityPromise;
|
|
4862
5041
|
}
|
|
4863
5042
|
function processStartIdentitiesMatch(recorded, current) {
|
|
5043
|
+
const format4 = PROCESS_START_IDENTITY_FORMATS.find((prefix) => current.startsWith(prefix));
|
|
5044
|
+
if (format4 === void 0 || !recorded.startsWith(format4)) {
|
|
5045
|
+
return void 0;
|
|
5046
|
+
}
|
|
4864
5047
|
return recorded === current;
|
|
4865
5048
|
}
|
|
4866
|
-
var WINDOWS_PROCESS_START_IDENTITY_PREFIX, PROCESS_START_IDENTITY_TIMEOUT_MS, DEFAULT_WINDOWS_SYSTEM_ROOT, currentProcessStartIdentityPromise, currentProcessStartIdentity;
|
|
5049
|
+
var WINDOWS_PROCESS_START_IDENTITY_PREFIX, POSIX_PROCESS_START_IDENTITY_PREFIX, LINUX_PROCESS_START_IDENTITY_PREFIX, PROCESS_START_IDENTITY_FORMATS, PROCESS_START_IDENTITY_TIMEOUT_MS, DEFAULT_WINDOWS_SYSTEM_ROOT, LINUX_BOOT_ID_PATH, LINUX_BOOT_ID_PATTERN, LINUX_STAT_START_TICKS_INDEX, currentProcessStartIdentityPromise, currentProcessStartIdentity;
|
|
4867
5050
|
var init_process_identity = __esm({
|
|
4868
5051
|
"dist/extensions/agent-browser/lib/process-identity.js"() {
|
|
4869
5052
|
"use strict";
|
|
5053
|
+
init_browser_execution_policy_debug();
|
|
4870
5054
|
WINDOWS_PROCESS_START_IDENTITY_PREFIX = "win32-powershell-ticks-v1:";
|
|
5055
|
+
POSIX_PROCESS_START_IDENTITY_PREFIX = "posix-ps-utc-v1:";
|
|
5056
|
+
LINUX_PROCESS_START_IDENTITY_PREFIX = "linux-proc-boot-ticks-v1:";
|
|
5057
|
+
PROCESS_START_IDENTITY_FORMATS = [
|
|
5058
|
+
WINDOWS_PROCESS_START_IDENTITY_PREFIX,
|
|
5059
|
+
POSIX_PROCESS_START_IDENTITY_PREFIX,
|
|
5060
|
+
LINUX_PROCESS_START_IDENTITY_PREFIX
|
|
5061
|
+
];
|
|
4871
5062
|
PROCESS_START_IDENTITY_TIMEOUT_MS = process.platform === "win32" ? 1e4 : 5e3;
|
|
4872
5063
|
DEFAULT_WINDOWS_SYSTEM_ROOT = "C:\\Windows";
|
|
5064
|
+
LINUX_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
|
|
5065
|
+
LINUX_BOOT_ID_PATTERN = /^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i;
|
|
5066
|
+
LINUX_STAT_START_TICKS_INDEX = 22 - 3;
|
|
4873
5067
|
}
|
|
4874
5068
|
});
|
|
4875
5069
|
|
|
4876
5070
|
// dist/extensions/agent-browser/lib/temp-root-ownership.js
|
|
4877
|
-
import { chmod, readFile, readdir, rm, stat as stat3, writeFile } from "node:fs/promises";
|
|
5071
|
+
import { chmod, readFile as readFile2, readdir, rm, stat as stat3, writeFile } from "node:fs/promises";
|
|
4878
5072
|
import { basename, dirname as dirname2, join as join2, resolve } from "node:path";
|
|
4879
5073
|
function getCurrentProcessUid2() {
|
|
4880
5074
|
return typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
@@ -4930,7 +5124,7 @@ function validOwnershipAndChildren(value) {
|
|
|
4930
5124
|
}
|
|
4931
5125
|
async function readTempRootOwnershipMarker(tempRoot) {
|
|
4932
5126
|
try {
|
|
4933
|
-
const markerText = await
|
|
5127
|
+
const markerText = await readFile2(join2(tempRoot, TEMP_ROOT_MARKER_FILE_NAME), "utf8");
|
|
4934
5128
|
const parsed = JSON.parse(markerText);
|
|
4935
5129
|
return isTempRootOwnershipRecord(parsed) ? parsed : void 0;
|
|
4936
5130
|
} catch {
|
|
@@ -5048,7 +5242,7 @@ async function refreshSecureTempRootLease(tempRoot) {
|
|
|
5048
5242
|
const currentProcessStartIdentity2 = await getProcessStartIdentity(process.pid);
|
|
5049
5243
|
if (ownershipMarker.ownerProcessStartIdentity !== void 0 && currentProcessStartIdentity2 !== void 0) {
|
|
5050
5244
|
const identitiesMatch = processStartIdentitiesMatch(ownershipMarker.ownerProcessStartIdentity, currentProcessStartIdentity2);
|
|
5051
|
-
if (
|
|
5245
|
+
if (identitiesMatch !== true) {
|
|
5052
5246
|
return;
|
|
5053
5247
|
}
|
|
5054
5248
|
}
|
|
@@ -5083,6 +5277,9 @@ async function getMarkerOwnerLiveness(ownershipMarker) {
|
|
|
5083
5277
|
return "unknown";
|
|
5084
5278
|
}
|
|
5085
5279
|
const identitiesMatch = processStartIdentitiesMatch(ownershipMarker.ownerProcessStartIdentity, currentProcessStartIdentity2);
|
|
5280
|
+
if (identitiesMatch === void 0) {
|
|
5281
|
+
return "unknown";
|
|
5282
|
+
}
|
|
5086
5283
|
return identitiesMatch ? "alive" : "dead";
|
|
5087
5284
|
}
|
|
5088
5285
|
var TEMP_ROOT_MARKER_FILE_NAME, TEMP_ROOT_MARKER_KIND, TEMP_ROOT_MARKER_VERSION;
|
|
@@ -5470,7 +5667,7 @@ var init_temp = __esm({
|
|
|
5470
5667
|
});
|
|
5471
5668
|
|
|
5472
5669
|
// dist/extensions/agent-browser/lib/process-environment.js
|
|
5473
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
5670
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
5474
5671
|
import { rm as rm5 } from "node:fs/promises";
|
|
5475
5672
|
function getAgentBrowserProcessEnvironment(baseEnv = process.env) {
|
|
5476
5673
|
const isolatedConfig = isolatedAgentBrowserEnvironment.getStore();
|
|
@@ -5518,8 +5715,8 @@ var init_process_environment = __esm({
|
|
|
5518
5715
|
"use strict";
|
|
5519
5716
|
init_argv_grammar();
|
|
5520
5717
|
init_temp();
|
|
5521
|
-
isolatedAgentBrowserEnvironment = new
|
|
5522
|
-
agentBrowserProcessEnvironment = new
|
|
5718
|
+
isolatedAgentBrowserEnvironment = new AsyncLocalStorage2();
|
|
5719
|
+
agentBrowserProcessEnvironment = new AsyncLocalStorage2();
|
|
5523
5720
|
PROXY_ENV_NAMES = /* @__PURE__ */ new Set(["ALL_PROXY", "HTTPS_PROXY", "HTTP_PROXY", "NO_PROXY"]);
|
|
5524
5721
|
}
|
|
5525
5722
|
});
|
|
@@ -5546,7 +5743,7 @@ var TARGET_AGENT_BROWSER_VERSION, TARGET_AGENT_BROWSER_VERSION_LABEL, MINIMUM_AG
|
|
|
5546
5743
|
var init_agent_browser_target = __esm({
|
|
5547
5744
|
"dist/scripts/agent-browser-target.mjs"() {
|
|
5548
5745
|
"use strict";
|
|
5549
|
-
TARGET_AGENT_BROWSER_VERSION = "0.
|
|
5746
|
+
TARGET_AGENT_BROWSER_VERSION = "0.41.0";
|
|
5550
5747
|
TARGET_AGENT_BROWSER_VERSION_LABEL = `agent-browser ${TARGET_AGENT_BROWSER_VERSION}`;
|
|
5551
5748
|
MINIMUM_AGENT_BROWSER_VERSION = "0.35.0";
|
|
5552
5749
|
MINIMUM_AGENT_BROWSER_VERSION_LABEL = `agent-browser ${MINIMUM_AGENT_BROWSER_VERSION}`;
|
|
@@ -6323,7 +6520,7 @@ var init_managed_session_storage = __esm({
|
|
|
6323
6520
|
});
|
|
6324
6521
|
|
|
6325
6522
|
// dist/extensions/agent-browser/lib/owned-managed-session-context.js
|
|
6326
|
-
import { AsyncLocalStorage as
|
|
6523
|
+
import { AsyncLocalStorage as AsyncLocalStorage3 } from "node:async_hooks";
|
|
6327
6524
|
async function withOwnedManagedSessionContext(context2, run) {
|
|
6328
6525
|
return await ownedManagedSessionStorage.run(context2, run);
|
|
6329
6526
|
}
|
|
@@ -6372,7 +6569,7 @@ var init_owned_managed_session_context = __esm({
|
|
|
6372
6569
|
"dist/extensions/agent-browser/lib/owned-managed-session-context.js"() {
|
|
6373
6570
|
"use strict";
|
|
6374
6571
|
init_argv_grammar();
|
|
6375
|
-
ownedManagedSessionStorage = new
|
|
6572
|
+
ownedManagedSessionStorage = new AsyncLocalStorage3();
|
|
6376
6573
|
}
|
|
6377
6574
|
});
|
|
6378
6575
|
|
|
@@ -6407,7 +6604,7 @@ function batchHasManagedSessionRestoreConflict(args, stdin) {
|
|
|
6407
6604
|
if (command !== "batch") {
|
|
6408
6605
|
return false;
|
|
6409
6606
|
}
|
|
6410
|
-
if (commandArgs.some((token) => token
|
|
6607
|
+
if (commandArgs.some((token) => !isNativeBatchOption(token))) {
|
|
6411
6608
|
return true;
|
|
6412
6609
|
}
|
|
6413
6610
|
const parsed = parseUserBatchStdin(stdin);
|
|
@@ -8954,7 +9151,7 @@ __export(lookup_workspace_exports, {
|
|
|
8954
9151
|
scanWorkspaceComponent: () => scanWorkspaceComponent,
|
|
8955
9152
|
scanWorkspaceRequests: () => scanWorkspaceRequests
|
|
8956
9153
|
});
|
|
8957
|
-
import { readFile as
|
|
9154
|
+
import { readFile as readFile3, readdir as readdir4 } from "node:fs/promises";
|
|
8958
9155
|
import { extname, join as join11 } from "node:path";
|
|
8959
9156
|
async function walkWorkspaceSourceFiles(root, maxFiles) {
|
|
8960
9157
|
const files = [];
|
|
@@ -8986,7 +9183,7 @@ async function walkWorkspaceSourceFiles(root, maxFiles) {
|
|
|
8986
9183
|
}
|
|
8987
9184
|
async function readWorkspaceText(file) {
|
|
8988
9185
|
try {
|
|
8989
|
-
return await
|
|
9186
|
+
return await readFile3(file, "utf8");
|
|
8990
9187
|
} catch {
|
|
8991
9188
|
return void 0;
|
|
8992
9189
|
}
|
|
@@ -9575,6 +9772,7 @@ var init_content = __esm({
|
|
|
9575
9772
|
"failures",
|
|
9576
9773
|
"artifacts",
|
|
9577
9774
|
"artifactVerification",
|
|
9775
|
+
"outputFile",
|
|
9578
9776
|
"imageObservations",
|
|
9579
9777
|
"fullOutputPath",
|
|
9580
9778
|
"fullOutputPaths",
|
|
@@ -10319,7 +10517,7 @@ var init_artifact_format = __esm({
|
|
|
10319
10517
|
});
|
|
10320
10518
|
|
|
10321
10519
|
// dist/extensions/agent-browser/lib/results/presentation/artifact-images.js
|
|
10322
|
-
import { readFile as
|
|
10520
|
+
import { readFile as readFile4, stat as stat7 } from "node:fs/promises";
|
|
10323
10521
|
import { resolve as resolve6 } from "node:path";
|
|
10324
10522
|
import { inspect as inspect2 } from "node:util";
|
|
10325
10523
|
import { getImageDimensions } from "@earendil-works/pi-tui";
|
|
@@ -10386,7 +10584,7 @@ async function attachVisibleImage(presentation, options) {
|
|
|
10386
10584
|
appendPresentationNotice(presentation, `Image attachment skipped: ${formatByteCount(options.size)} exceeds the inline limit of ${formatByteCount(limit)}.`);
|
|
10387
10585
|
return;
|
|
10388
10586
|
}
|
|
10389
|
-
const file = await
|
|
10587
|
+
const file = await readFile4(options.imagePath);
|
|
10390
10588
|
presentation.content.push({
|
|
10391
10589
|
type: "image",
|
|
10392
10590
|
data: file.toString("base64"),
|
|
@@ -10956,6 +11154,8 @@ function buildCompactObservation(observation2, persisted) {
|
|
|
10956
11154
|
"sessionName",
|
|
10957
11155
|
"namespace",
|
|
10958
11156
|
"codeRun",
|
|
11157
|
+
// A requested outputPath receipt is small and confirms the caller's side effect; keep it ahead of bulky fields.
|
|
11158
|
+
"outputFile",
|
|
10959
11159
|
"error",
|
|
10960
11160
|
"failures",
|
|
10961
11161
|
"nextActions",
|
|
@@ -10998,7 +11198,7 @@ async function renderAgentBrowserObservation(options) {
|
|
|
10998
11198
|
let structuredContent = observation2;
|
|
10999
11199
|
const images = options.content.filter((part) => part.type === "image");
|
|
11000
11200
|
const prose = options.content.filter((part) => part.type === "text").map((part) => part.text).join("\n\n");
|
|
11001
|
-
const { data: _data, error: _error, summary: _summary, ...metadata } = observation2;
|
|
11201
|
+
const { data: _data, error: _error, summary: _summary, outputFile: _outputFile, ...metadata } = observation2;
|
|
11002
11202
|
let text3 = options.json ? JSON.stringify(observation2, null, 2) : `${prose}
|
|
11003
11203
|
|
|
11004
11204
|
Observation: ${JSON.stringify(metadata)}`;
|
|
@@ -11984,6 +12184,7 @@ var init_process_stdout = __esm({
|
|
|
11984
12184
|
// dist/extensions/agent-browser/lib/process-child.js
|
|
11985
12185
|
import { spawn } from "node:child_process";
|
|
11986
12186
|
import { platform as processPlatform } from "node:process";
|
|
12187
|
+
import { constants as constants3 } from "node:os";
|
|
11987
12188
|
import { spawn as crossSpawn } from "cross-spawn";
|
|
11988
12189
|
async function terminateSpawnedChild(child, signal) {
|
|
11989
12190
|
if (processPlatform === "win32" && child.pid !== void 0 && child.pid !== 0) {
|
|
@@ -12010,6 +12211,9 @@ function resolveSpawnedChildExitCode(input) {
|
|
|
12010
12211
|
if (input.useExitFallback && input.exitCode !== null && input.exitCode !== void 0) {
|
|
12011
12212
|
return input.exitCode;
|
|
12012
12213
|
}
|
|
12214
|
+
if (input.exitSignal !== null && input.exitSignal !== void 0) {
|
|
12215
|
+
return 128 + constants3.signals[input.exitSignal];
|
|
12216
|
+
}
|
|
12013
12217
|
return input.spawnError ? 127 : 0;
|
|
12014
12218
|
}
|
|
12015
12219
|
function destroySpawnedChildStreams(child) {
|
|
@@ -12049,21 +12253,24 @@ var init_process_child = __esm({
|
|
|
12049
12253
|
context;
|
|
12050
12254
|
exited = false;
|
|
12051
12255
|
exitCode = null;
|
|
12256
|
+
exitSignal = null;
|
|
12052
12257
|
timer;
|
|
12053
12258
|
completed = false;
|
|
12054
12259
|
constructor(child, complete, context2) {
|
|
12055
12260
|
this.complete = complete;
|
|
12056
12261
|
this.context = context2;
|
|
12057
|
-
child.once("exit", (code) => {
|
|
12262
|
+
child.once("exit", (code, signal) => {
|
|
12058
12263
|
this.exited = true;
|
|
12059
12264
|
this.exitCode = code;
|
|
12265
|
+
this.exitSignal = signal;
|
|
12060
12266
|
this.timer = setTimeout(() => {
|
|
12061
12267
|
destroySpawnedChildStreams(child);
|
|
12062
12268
|
this.finish();
|
|
12063
12269
|
}, EXIT_STDIO_GRACE_MS);
|
|
12064
12270
|
this.timer.unref();
|
|
12065
12271
|
});
|
|
12066
|
-
child.once("close", (code) => {
|
|
12272
|
+
child.once("close", (code, signal) => {
|
|
12273
|
+
this.exitSignal = signal ?? this.exitSignal;
|
|
12067
12274
|
this.finish(code);
|
|
12068
12275
|
});
|
|
12069
12276
|
}
|
|
@@ -12077,10 +12284,11 @@ var init_process_child = __esm({
|
|
|
12077
12284
|
this.complete(resolveSpawnedChildExitCode({
|
|
12078
12285
|
closeCode,
|
|
12079
12286
|
exitCode: this.exitCode,
|
|
12287
|
+
exitSignal: this.exitSignal,
|
|
12080
12288
|
useExitFallback: this.exited,
|
|
12081
12289
|
timedOut: context2.timedOut,
|
|
12082
12290
|
spawnError: context2.spawnError
|
|
12083
|
-
}));
|
|
12291
|
+
}), this.exitSignal ?? void 0);
|
|
12084
12292
|
}
|
|
12085
12293
|
clear() {
|
|
12086
12294
|
if (this.timer) {
|
|
@@ -12096,6 +12304,7 @@ var init_process_child = __esm({
|
|
|
12096
12304
|
agentBrowserStarted = false;
|
|
12097
12305
|
settled = false;
|
|
12098
12306
|
spawnError;
|
|
12307
|
+
exitSignal;
|
|
12099
12308
|
stderr = "";
|
|
12100
12309
|
stdout = new ProcessStdout();
|
|
12101
12310
|
pendingTermination;
|
|
@@ -12142,8 +12351,8 @@ var init_process_child = __esm({
|
|
|
12142
12351
|
spawnError: this.spawnError
|
|
12143
12352
|
}));
|
|
12144
12353
|
});
|
|
12145
|
-
this.completion = new ChildCompletion(child, (code) => {
|
|
12146
|
-
this.finish(code);
|
|
12354
|
+
this.completion = new ChildCompletion(child, (code, signal) => {
|
|
12355
|
+
this.finish(code, signal);
|
|
12147
12356
|
}, () => ({ timedOut: this.timedOut, spawnError: this.spawnError }));
|
|
12148
12357
|
child.stdout.on("data", (chunk) => {
|
|
12149
12358
|
this.stdout.queue(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -12212,11 +12421,12 @@ var init_process_child = __esm({
|
|
|
12212
12421
|
this.child.stdin.destroy();
|
|
12213
12422
|
}
|
|
12214
12423
|
}
|
|
12215
|
-
finish(exitCode) {
|
|
12424
|
+
finish(exitCode, exitSignal) {
|
|
12216
12425
|
if (this.settled) {
|
|
12217
12426
|
return;
|
|
12218
12427
|
}
|
|
12219
12428
|
this.settled = true;
|
|
12429
|
+
this.exitSignal = exitSignal;
|
|
12220
12430
|
if (this.abortListener) {
|
|
12221
12431
|
this.options.signal?.removeEventListener("abort", this.abortListener);
|
|
12222
12432
|
this.abortListener = void 0;
|
|
@@ -12250,6 +12460,7 @@ var init_process_child = __esm({
|
|
|
12250
12460
|
aborted: this.aborted,
|
|
12251
12461
|
agentBrowserStarted: this.agentBrowserStarted,
|
|
12252
12462
|
exitCode,
|
|
12463
|
+
exitSignal: this.exitSignal,
|
|
12253
12464
|
spawnError: this.spawnError,
|
|
12254
12465
|
stderr: this.stderr,
|
|
12255
12466
|
stdout,
|
|
@@ -12337,7 +12548,7 @@ function getBatchCommandSteps(args, stdin) {
|
|
|
12337
12548
|
if (descriptor.commandInfo.command !== "batch") {
|
|
12338
12549
|
return { steps: [] };
|
|
12339
12550
|
}
|
|
12340
|
-
const argumentsToParse = descriptor.upstreamCommandTokens.slice(1).filter((command) => command
|
|
12551
|
+
const argumentsToParse = descriptor.upstreamCommandTokens.slice(1).filter((command) => !isNativeBatchOption(command));
|
|
12341
12552
|
if (argumentsToParse.length > 0) {
|
|
12342
12553
|
return inspectBatchArguments(argumentsToParse);
|
|
12343
12554
|
}
|
|
@@ -12839,7 +13050,7 @@ var init_process_socket_storage = __esm({
|
|
|
12839
13050
|
});
|
|
12840
13051
|
|
|
12841
13052
|
// dist/extensions/agent-browser/lib/process.js
|
|
12842
|
-
import { AsyncLocalStorage as
|
|
13053
|
+
import { AsyncLocalStorage as AsyncLocalStorage5 } from "node:async_hooks";
|
|
12843
13054
|
import { env as processEnv2 } from "node:process";
|
|
12844
13055
|
function withChromeStartupArgs(args, run) {
|
|
12845
13056
|
return chromeStartupArgsContext.run(args ?? chromeStartupArgsContext.getStore(), run);
|
|
@@ -13037,8 +13248,8 @@ var init_process = __esm({
|
|
|
13037
13248
|
PI_AGENT_BROWSER_PROCESS_TIMEOUT_ENV = "PI_AGENT_BROWSER_PROCESS_TIMEOUT_MS";
|
|
13038
13249
|
SAFE_AGENT_BROWSER_OPERATION_TIMEOUT_MS = 25e3;
|
|
13039
13250
|
DEFAULT_AGENT_BROWSER_PROCESS_TIMEOUT_MS = 35e3;
|
|
13040
|
-
attachedBrowserSessionContext = new
|
|
13041
|
-
chromeStartupArgsContext = new
|
|
13251
|
+
attachedBrowserSessionContext = new AsyncLocalStorage5();
|
|
13252
|
+
chromeStartupArgsContext = new AsyncLocalStorage5();
|
|
13042
13253
|
}
|
|
13043
13254
|
});
|
|
13044
13255
|
|
|
@@ -13098,7 +13309,7 @@ var init_envelope_decoding = __esm({
|
|
|
13098
13309
|
});
|
|
13099
13310
|
|
|
13100
13311
|
// dist/extensions/agent-browser/lib/results/envelope.js
|
|
13101
|
-
import { readFile as
|
|
13312
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
13102
13313
|
function hasStructuredBatchStepFailure(data) {
|
|
13103
13314
|
return Array.isArray(data) && data.some((item) => isRecord(item) && item.success === false);
|
|
13104
13315
|
}
|
|
@@ -13107,7 +13318,7 @@ async function readEnvelopeSource(options) {
|
|
|
13107
13318
|
return options.stdout;
|
|
13108
13319
|
}
|
|
13109
13320
|
try {
|
|
13110
|
-
return await
|
|
13321
|
+
return await readFile6(options.stdoutPath, "utf8");
|
|
13111
13322
|
} catch (error) {
|
|
13112
13323
|
const message = error instanceof Error ? error.message : stringifyUnknown(error);
|
|
13113
13324
|
throw new Error(`agent-browser output spill file could not be read: ${message}`, {
|
|
@@ -13232,10 +13443,24 @@ function getTransportErrorText(options) {
|
|
|
13232
13443
|
return options.spawnError.message;
|
|
13233
13444
|
}
|
|
13234
13445
|
if ((options.parseError ?? "") !== "") {
|
|
13235
|
-
return
|
|
13446
|
+
return malformedProcessErrorText(options);
|
|
13236
13447
|
}
|
|
13237
13448
|
return void 0;
|
|
13238
13449
|
}
|
|
13450
|
+
function malformedProcessErrorText(options) {
|
|
13451
|
+
if (options.exitCode === 0 && options.exitSignal === void 0) {
|
|
13452
|
+
return options.parseError;
|
|
13453
|
+
}
|
|
13454
|
+
const signalText = options.exitSignal === void 0 ? void 0 : `Signal: ${options.exitSignal}.`;
|
|
13455
|
+
const oomHint = options.exitSignal === "SIGKILL" || options.exitCode === 137 ? "SIGKILL may indicate an OOM kill or an external stop. Inspect the host kernel log and cgroup memory.events before retrying; the command may have executed." : void 0;
|
|
13456
|
+
return [
|
|
13457
|
+
buildExitCodeFallback(options),
|
|
13458
|
+
signalText,
|
|
13459
|
+
options.stderr.trim(),
|
|
13460
|
+
options.stderr.trim().length > 0 ? void 0 : options.parseError,
|
|
13461
|
+
oomHint
|
|
13462
|
+
].filter(Boolean).join("\n");
|
|
13463
|
+
}
|
|
13239
13464
|
function getEnvelopeDataError(data) {
|
|
13240
13465
|
if (typeof data === "string") {
|
|
13241
13466
|
return data;
|
|
@@ -13286,7 +13511,7 @@ var init_envelope = __esm({
|
|
|
13286
13511
|
});
|
|
13287
13512
|
|
|
13288
13513
|
// dist/extensions/agent-browser/lib/webmcp-observation.js
|
|
13289
|
-
import { AsyncLocalStorage as
|
|
13514
|
+
import { AsyncLocalStorage as AsyncLocalStorage6 } from "node:async_hooks";
|
|
13290
13515
|
function getNativeWebMcpCatalog(data) {
|
|
13291
13516
|
if (Array.isArray(data)) {
|
|
13292
13517
|
for (let index = data.length - 1; index >= 0; index -= 1) {
|
|
@@ -13321,12 +13546,12 @@ var init_webmcp_observation = __esm({
|
|
|
13321
13546
|
"dist/extensions/agent-browser/lib/webmcp-observation.js"() {
|
|
13322
13547
|
"use strict";
|
|
13323
13548
|
init_parsing();
|
|
13324
|
-
observation = new
|
|
13549
|
+
observation = new AsyncLocalStorage6();
|
|
13325
13550
|
}
|
|
13326
13551
|
});
|
|
13327
13552
|
|
|
13328
13553
|
// dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js
|
|
13329
|
-
import { AsyncLocalStorage as
|
|
13554
|
+
import { AsyncLocalStorage as AsyncLocalStorage7 } from "node:async_hooks";
|
|
13330
13555
|
import { rm as rm6 } from "node:fs/promises";
|
|
13331
13556
|
function withSessionCommandObservation(observer, run) {
|
|
13332
13557
|
return sessionCommandObservation.run(observer, run);
|
|
@@ -13441,7 +13666,7 @@ var init_session_state_commands = __esm({
|
|
|
13441
13666
|
init_confirmation();
|
|
13442
13667
|
init_envelope();
|
|
13443
13668
|
init_webmcp_observation();
|
|
13444
|
-
sessionCommandObservation = new
|
|
13669
|
+
sessionCommandObservation = new AsyncLocalStorage7();
|
|
13445
13670
|
}
|
|
13446
13671
|
});
|
|
13447
13672
|
|
|
@@ -15016,7 +15241,7 @@ function hasProcessExited(child, pid) {
|
|
|
15016
15241
|
return child ? child.exitCode !== null || child.signalCode !== null : isPidAlive(pid) === false;
|
|
15017
15242
|
}
|
|
15018
15243
|
async function waitForProcessExit(child, pid, deadlineMs) {
|
|
15019
|
-
while (
|
|
15244
|
+
while (performance.now() <= deadlineMs) {
|
|
15020
15245
|
if (hasProcessExited(child, pid)) {
|
|
15021
15246
|
return true;
|
|
15022
15247
|
}
|
|
@@ -15032,7 +15257,7 @@ async function getRestoredProcessVerificationError(record) {
|
|
|
15032
15257
|
if (currentIdentity === void 0) {
|
|
15033
15258
|
return `PID ${String(record.pid)} is alive, but its current start identity could not be inspected; refusing to signal a restored PID that may have been reused.`;
|
|
15034
15259
|
}
|
|
15035
|
-
if (
|
|
15260
|
+
if (processStartIdentitiesMatch(record.startIdentity, currentIdentity) !== true) {
|
|
15036
15261
|
return `PID ${String(record.pid)} is alive, but its start identity does not match the wrapper launch record; refusing to signal a restored PID that may have been reused.`;
|
|
15037
15262
|
}
|
|
15038
15263
|
return void 0;
|
|
@@ -15091,7 +15316,7 @@ async function cleanupRestoredProcess(record, deadlineMs) {
|
|
|
15091
15316
|
return { error: killVerificationError, resource: "process", state: "failed" };
|
|
15092
15317
|
}
|
|
15093
15318
|
signalRestoredLaunchProcess(record, "SIGKILL");
|
|
15094
|
-
if (await waitForProcessExit(void 0, record.pid,
|
|
15319
|
+
if (await waitForProcessExit(void 0, record.pid, performance.now() + 1e3)) {
|
|
15095
15320
|
return { resource: "process", state: "removed" };
|
|
15096
15321
|
}
|
|
15097
15322
|
return {
|
|
@@ -15114,7 +15339,7 @@ async function cleanupTrackedProcess(record, child, deadlineMs) {
|
|
|
15114
15339
|
} else {
|
|
15115
15340
|
killPid(record.pid, "SIGKILL");
|
|
15116
15341
|
}
|
|
15117
|
-
if (await waitForProcessExit(child, record.pid,
|
|
15342
|
+
if (await waitForProcessExit(child, record.pid, performance.now() + 1e3)) {
|
|
15118
15343
|
return { resource: "process", state: "removed" };
|
|
15119
15344
|
}
|
|
15120
15345
|
return {
|
|
@@ -15176,7 +15401,7 @@ function summarizeCleanup(launchId, steps) {
|
|
|
15176
15401
|
}
|
|
15177
15402
|
async function cleanupElectronLaunchResources(options) {
|
|
15178
15403
|
const timeoutMs = typeof options.timeoutMs === "number" && Number.isSafeInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS;
|
|
15179
|
-
const deadlineMs =
|
|
15404
|
+
const deadlineMs = performance.now() + timeoutMs;
|
|
15180
15405
|
const processStep = await cleanupProcess(options.record, options.child, deadlineMs);
|
|
15181
15406
|
const debugPortStep = await cleanupDebugPort(options.record);
|
|
15182
15407
|
const userDataDirSkipReason = shouldSkipUserDataDirCleanup(processStep, debugPortStep);
|
|
@@ -15298,17 +15523,25 @@ function directoryOwnerTrusted(entry, platform) {
|
|
|
15298
15523
|
return uid !== void 0 && entry.uid === uid && (entry.mode & 63) === 0;
|
|
15299
15524
|
}
|
|
15300
15525
|
async function ensureCoordinationDirectory(path, platform) {
|
|
15526
|
+
let stage = "prepare.directory-mkdir";
|
|
15301
15527
|
try {
|
|
15302
15528
|
try {
|
|
15303
15529
|
await mkdir3(path, { mode: 448 });
|
|
15304
15530
|
} catch (error) {
|
|
15305
15531
|
if (getErrorCode(error) !== "EEXIST") {
|
|
15532
|
+
debugPolicyFailure(stage, "native-error", error);
|
|
15306
15533
|
return false;
|
|
15307
15534
|
}
|
|
15308
15535
|
}
|
|
15536
|
+
stage = "prepare.directory-stat";
|
|
15309
15537
|
const entry = await lstat3(path);
|
|
15310
|
-
|
|
15311
|
-
|
|
15538
|
+
const trusted = !entry.isSymbolicLink() && entry.isDirectory() && directoryOwnerTrusted(entry, platform);
|
|
15539
|
+
if (!trusted) {
|
|
15540
|
+
debugPolicyFailure(stage, "unsafe-metadata");
|
|
15541
|
+
}
|
|
15542
|
+
return trusted;
|
|
15543
|
+
} catch (error) {
|
|
15544
|
+
debugPolicyFailure(stage, "native-error", error);
|
|
15312
15545
|
return false;
|
|
15313
15546
|
}
|
|
15314
15547
|
}
|
|
@@ -15344,13 +15577,143 @@ var init_browser_execution_identity = __esm({
|
|
|
15344
15577
|
init_process_socket_storage();
|
|
15345
15578
|
init_process_identity();
|
|
15346
15579
|
init_process_errors();
|
|
15580
|
+
init_browser_execution_policy_debug();
|
|
15581
|
+
}
|
|
15582
|
+
});
|
|
15583
|
+
|
|
15584
|
+
// dist/extensions/agent-browser/lib/browser-execution-claim-endpoint.js
|
|
15585
|
+
import { unlink } from "node:fs/promises";
|
|
15586
|
+
import { createConnection, createServer } from "node:net";
|
|
15587
|
+
import { dirname as dirname11, join as join19 } from "node:path";
|
|
15588
|
+
function claimEndpointPath(claimPath, token) {
|
|
15589
|
+
return join19(dirname11(claimPath), `.l-${token}`);
|
|
15590
|
+
}
|
|
15591
|
+
function openClaimEndpoint(claimPath, token) {
|
|
15592
|
+
if (!endpointsSupported) {
|
|
15593
|
+
return void 0;
|
|
15594
|
+
}
|
|
15595
|
+
const server = createServer();
|
|
15596
|
+
const subscribers = /* @__PURE__ */ new Set();
|
|
15597
|
+
let closed = false;
|
|
15598
|
+
const close = () => {
|
|
15599
|
+
if (closed) {
|
|
15600
|
+
return;
|
|
15601
|
+
}
|
|
15602
|
+
closed = true;
|
|
15603
|
+
server.close();
|
|
15604
|
+
for (const subscriber of subscribers) {
|
|
15605
|
+
subscriber.destroy();
|
|
15606
|
+
}
|
|
15607
|
+
subscribers.clear();
|
|
15608
|
+
};
|
|
15609
|
+
server.on("connection", (subscriber) => {
|
|
15610
|
+
subscriber.unref();
|
|
15611
|
+
subscribers.add(subscriber);
|
|
15612
|
+
subscriber.on("error", () => {
|
|
15613
|
+
});
|
|
15614
|
+
subscriber.on("close", () => {
|
|
15615
|
+
subscribers.delete(subscriber);
|
|
15616
|
+
});
|
|
15617
|
+
subscriber.resume();
|
|
15618
|
+
});
|
|
15619
|
+
server.on("error", (error) => {
|
|
15620
|
+
debugPolicyFailure("endpoint.listen", "native-error", error);
|
|
15621
|
+
close();
|
|
15622
|
+
});
|
|
15623
|
+
server.unref();
|
|
15624
|
+
server.listen(claimEndpointPath(claimPath, token));
|
|
15625
|
+
return { close };
|
|
15626
|
+
}
|
|
15627
|
+
async function removeClaimEndpoint(claimPath, token) {
|
|
15628
|
+
if (!endpointsSupported) {
|
|
15629
|
+
return;
|
|
15630
|
+
}
|
|
15631
|
+
try {
|
|
15632
|
+
await unlink(claimEndpointPath(claimPath, token));
|
|
15633
|
+
} catch (error) {
|
|
15634
|
+
if (getErrorCode(error) !== "ENOENT") {
|
|
15635
|
+
debugPolicyFailure("endpoint.unlink", "native-error", error);
|
|
15636
|
+
}
|
|
15637
|
+
}
|
|
15638
|
+
}
|
|
15639
|
+
function sleep2(signal, deadline, setWake) {
|
|
15640
|
+
return new Promise((resolve19) => {
|
|
15641
|
+
const timer = setTimeout(done, Math.max(0, Math.min(deadline - performance.now(), MAX_TIMER_MS)));
|
|
15642
|
+
function done() {
|
|
15643
|
+
clearTimeout(timer);
|
|
15644
|
+
signal?.removeEventListener("abort", done);
|
|
15645
|
+
setWake(void 0);
|
|
15646
|
+
resolve19();
|
|
15647
|
+
}
|
|
15648
|
+
setWake(done);
|
|
15649
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
15650
|
+
if (signal?.aborted === true) {
|
|
15651
|
+
done();
|
|
15652
|
+
}
|
|
15653
|
+
});
|
|
15654
|
+
}
|
|
15655
|
+
async function subscribeClaimEndpoint(claimPath, token, signal, deadline) {
|
|
15656
|
+
if (!endpointsSupported) {
|
|
15657
|
+
return void 0;
|
|
15658
|
+
}
|
|
15659
|
+
let connected = false;
|
|
15660
|
+
let disconnected = false;
|
|
15661
|
+
let wake;
|
|
15662
|
+
const open6 = () => connected && !disconnected;
|
|
15663
|
+
const setWake = (next) => {
|
|
15664
|
+
wake = next;
|
|
15665
|
+
};
|
|
15666
|
+
const socket = createConnection(claimEndpointPath(claimPath, token));
|
|
15667
|
+
socket.on("error", (error) => {
|
|
15668
|
+
if (!connected) {
|
|
15669
|
+
debugPolicyFailure("endpoint.connect", "unavailable", error);
|
|
15670
|
+
}
|
|
15671
|
+
disconnected = true;
|
|
15672
|
+
wake?.();
|
|
15673
|
+
});
|
|
15674
|
+
socket.on("close", () => {
|
|
15675
|
+
disconnected = true;
|
|
15676
|
+
wake?.();
|
|
15677
|
+
});
|
|
15678
|
+
socket.once("connect", () => {
|
|
15679
|
+
connected = true;
|
|
15680
|
+
wake?.();
|
|
15681
|
+
});
|
|
15682
|
+
await sleep2(signal, deadline, setWake);
|
|
15683
|
+
if (!open6()) {
|
|
15684
|
+
socket.destroy();
|
|
15685
|
+
return void 0;
|
|
15686
|
+
}
|
|
15687
|
+
socket.resume();
|
|
15688
|
+
return {
|
|
15689
|
+
token,
|
|
15690
|
+
connected: open6,
|
|
15691
|
+
wait: async (waitSignal, waitDeadline) => {
|
|
15692
|
+
if (!disconnected) {
|
|
15693
|
+
await sleep2(waitSignal, waitDeadline, setWake);
|
|
15694
|
+
}
|
|
15695
|
+
},
|
|
15696
|
+
close: () => {
|
|
15697
|
+
wake = void 0;
|
|
15698
|
+
socket.destroy();
|
|
15699
|
+
}
|
|
15700
|
+
};
|
|
15701
|
+
}
|
|
15702
|
+
var endpointsSupported, MAX_TIMER_MS;
|
|
15703
|
+
var init_browser_execution_claim_endpoint = __esm({
|
|
15704
|
+
"dist/extensions/agent-browser/lib/browser-execution-claim-endpoint.js"() {
|
|
15705
|
+
"use strict";
|
|
15706
|
+
init_browser_execution_policy_debug();
|
|
15707
|
+
init_process_errors();
|
|
15708
|
+
endpointsSupported = process.platform !== "win32";
|
|
15709
|
+
MAX_TIMER_MS = 2147483647;
|
|
15347
15710
|
}
|
|
15348
15711
|
});
|
|
15349
15712
|
|
|
15350
15713
|
// dist/extensions/agent-browser/lib/browser-execution-claim-storage.js
|
|
15351
15714
|
import { randomInt as randomInt2, randomUUID as randomUUID6 } from "node:crypto";
|
|
15352
|
-
import { lstat as lstat4, readFile as
|
|
15353
|
-
import { basename as basename5, dirname as
|
|
15715
|
+
import { lstat as lstat4, readFile as readFile7, readdir as readdir6, rename, rm as rm8 } from "node:fs/promises";
|
|
15716
|
+
import { basename as basename5, dirname as dirname12, join as join20 } from "node:path";
|
|
15354
15717
|
function secureEntry(entry, directory) {
|
|
15355
15718
|
if (entry.isSymbolicLink() || (directory ? !entry.isDirectory() : !entry.isFile())) {
|
|
15356
15719
|
return false;
|
|
@@ -15367,60 +15730,99 @@ function secureEntryOwnership(entry, mask) {
|
|
|
15367
15730
|
const uid = typeof process.getuid === "function" ? process.getuid() : void 0;
|
|
15368
15731
|
return uid !== void 0 && entry.uid === uid && (entry.mode & mask) === 0;
|
|
15369
15732
|
}
|
|
15370
|
-
async function readClaimTicket(path, owner) {
|
|
15371
|
-
const ticketPath =
|
|
15733
|
+
async function readClaimTicket(path, owner, report) {
|
|
15734
|
+
const ticketPath = join20(path, LOCK_TICKET_FILE);
|
|
15735
|
+
let stage = "claim.ticket-stat";
|
|
15372
15736
|
try {
|
|
15373
15737
|
if (!secureEntry(await lstat4(ticketPath), false)) {
|
|
15738
|
+
report?.(stage, "unsafe-metadata");
|
|
15374
15739
|
return void 0;
|
|
15375
15740
|
}
|
|
15376
|
-
|
|
15741
|
+
stage = "claim.ticket-read";
|
|
15742
|
+
const ticket = parseTicket(await readFile7(ticketPath, "utf8"), owner.token);
|
|
15743
|
+
if (ticket === void 0) {
|
|
15744
|
+
report?.(stage, "invalid-ticket-or-token");
|
|
15745
|
+
}
|
|
15377
15746
|
return ticket === void 0 ? void 0 : { owner, path, ticket };
|
|
15378
15747
|
} catch (error) {
|
|
15379
|
-
|
|
15748
|
+
const code = getErrorCode(error);
|
|
15749
|
+
if (code !== "ENOENT") {
|
|
15750
|
+
report?.(stage, "native-error", error);
|
|
15751
|
+
}
|
|
15752
|
+
return code === "ENOENT" ? { owner, path, ticket: null } : void 0;
|
|
15380
15753
|
}
|
|
15381
15754
|
}
|
|
15382
|
-
async function
|
|
15755
|
+
async function inspectClaim(path, report) {
|
|
15756
|
+
let stage = "claim.directory-stat";
|
|
15383
15757
|
try {
|
|
15384
15758
|
const directory = await lstat4(path);
|
|
15385
|
-
const ownerPath =
|
|
15759
|
+
const ownerPath = join20(path, LOCK_OWNER_FILE);
|
|
15760
|
+
stage = "claim.owner-stat";
|
|
15386
15761
|
const ownerEntry = await lstat4(ownerPath);
|
|
15387
15762
|
if (!secureEntry(directory, true) || !secureEntry(ownerEntry, false)) {
|
|
15763
|
+
report?.("claim.metadata", "unsafe-directory-or-owner");
|
|
15388
15764
|
return void 0;
|
|
15389
15765
|
}
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15766
|
+
stage = "claim.owner-read";
|
|
15767
|
+
const owner = parseOwner(await readFile7(ownerPath, "utf8"));
|
|
15768
|
+
if (!owner) {
|
|
15769
|
+
report?.(stage, "invalid-owner");
|
|
15770
|
+
}
|
|
15771
|
+
return owner ? await readClaimTicket(path, owner, report) : void 0;
|
|
15772
|
+
} catch (error) {
|
|
15773
|
+
report?.(stage, "native-error", error);
|
|
15393
15774
|
return void 0;
|
|
15394
15775
|
}
|
|
15395
15776
|
}
|
|
15777
|
+
function reportDirectClaimFailure(stage, reason, error) {
|
|
15778
|
+
if (getErrorCode(error) !== "ENOENT") {
|
|
15779
|
+
debugPolicyFailure(stage, reason, error);
|
|
15780
|
+
}
|
|
15781
|
+
}
|
|
15782
|
+
function readClaim(path) {
|
|
15783
|
+
return inspectClaim(path, policyDebugEnabled ? reportDirectClaimFailure : void 0);
|
|
15784
|
+
}
|
|
15396
15785
|
async function claimDisappeared(path) {
|
|
15397
15786
|
try {
|
|
15398
15787
|
await lstat4(path);
|
|
15399
15788
|
return false;
|
|
15400
15789
|
} catch (error) {
|
|
15401
|
-
|
|
15790
|
+
const code = getErrorCode(error);
|
|
15791
|
+
if (code !== "ENOENT") {
|
|
15792
|
+
debugPolicyFailure("claims.absence-stat", "absence-not-confirmed", error);
|
|
15793
|
+
}
|
|
15794
|
+
return code === "ENOENT";
|
|
15402
15795
|
}
|
|
15403
15796
|
}
|
|
15404
15797
|
async function readClaims(basePath) {
|
|
15405
|
-
const directory =
|
|
15798
|
+
const directory = dirname12(basePath);
|
|
15406
15799
|
const prefix = `${basename5(basePath)}.claim-`;
|
|
15407
15800
|
let names;
|
|
15408
15801
|
try {
|
|
15409
15802
|
names = await readdir6(directory);
|
|
15410
|
-
} catch {
|
|
15803
|
+
} catch (error) {
|
|
15804
|
+
debugPolicyFailure("claims.readdir", "native-error", error);
|
|
15411
15805
|
return void 0;
|
|
15412
15806
|
}
|
|
15413
15807
|
const claims = [];
|
|
15414
15808
|
for (const name of names.filter((candidate) => candidate.startsWith(prefix))) {
|
|
15415
|
-
const path =
|
|
15416
|
-
|
|
15809
|
+
const path = join20(directory, name);
|
|
15810
|
+
let failure;
|
|
15811
|
+
const claim = await inspectClaim(path, policyDebugEnabled ? (stage, reason, error) => {
|
|
15812
|
+
failure = { stage, reason, error: policyDebugError(error) };
|
|
15813
|
+
} : void 0);
|
|
15417
15814
|
if (!claim) {
|
|
15418
15815
|
if (await claimDisappeared(path)) {
|
|
15419
15816
|
continue;
|
|
15420
15817
|
}
|
|
15818
|
+
if (failure !== void 0) {
|
|
15819
|
+
debugPolicyFailure(failure.stage, failure.reason, failure.error);
|
|
15820
|
+
}
|
|
15821
|
+
debugPolicyFailure("claims.inspect", "absence-not-confirmed");
|
|
15421
15822
|
return void 0;
|
|
15422
15823
|
}
|
|
15423
15824
|
if (name !== `${prefix}${claim.owner.token}`) {
|
|
15825
|
+
debugPolicyFailure("claims.inspect", "published-owner-token-mismatch");
|
|
15424
15826
|
return void 0;
|
|
15425
15827
|
}
|
|
15426
15828
|
claims.push(claim);
|
|
@@ -15436,6 +15838,7 @@ async function ownerAlive(owner, budget) {
|
|
|
15436
15838
|
return false;
|
|
15437
15839
|
}
|
|
15438
15840
|
if (code !== "EPERM") {
|
|
15841
|
+
debugPolicyFailure("owner.liveness", "native-error", error);
|
|
15439
15842
|
return void 0;
|
|
15440
15843
|
}
|
|
15441
15844
|
}
|
|
@@ -15460,6 +15863,7 @@ function waitForRetry(signal) {
|
|
|
15460
15863
|
async function moveOwnedClaim(path, movedPath, token, deadline) {
|
|
15461
15864
|
while (true) {
|
|
15462
15865
|
if ((await readClaim(path))?.owner.token !== token) {
|
|
15866
|
+
debugPolicyFailure("remove.verify", "owner-missing-or-token-mismatch");
|
|
15463
15867
|
return void 0;
|
|
15464
15868
|
}
|
|
15465
15869
|
try {
|
|
@@ -15470,18 +15874,20 @@ async function moveOwnedClaim(path, movedPath, token, deadline) {
|
|
|
15470
15874
|
if (code === "ENOENT") {
|
|
15471
15875
|
return "absent";
|
|
15472
15876
|
}
|
|
15473
|
-
if (process.platform !== "win32" || code !== "EPERM" ||
|
|
15877
|
+
if (process.platform !== "win32" || code !== "EPERM" || performance.now() >= deadline) {
|
|
15878
|
+
debugPolicyFailure("remove.rename", "native-error", error);
|
|
15474
15879
|
return void 0;
|
|
15475
15880
|
}
|
|
15476
15881
|
await waitForRetry();
|
|
15477
|
-
if (
|
|
15882
|
+
if (performance.now() >= deadline) {
|
|
15883
|
+
debugPolicyFailure("remove.rename", "retry-deadline", error);
|
|
15478
15884
|
return void 0;
|
|
15479
15885
|
}
|
|
15480
15886
|
}
|
|
15481
15887
|
}
|
|
15482
15888
|
}
|
|
15483
15889
|
async function removeClaimOwnedBy(path, token, deadline = 0) {
|
|
15484
|
-
const movedPath =
|
|
15890
|
+
const movedPath = join20(dirname12(path), `.pi-agent-browser-policy-remove-${token}-${randomUUID6()}`);
|
|
15485
15891
|
const movement = await moveOwnedClaim(path, movedPath, token, deadline);
|
|
15486
15892
|
if (movement === "absent") {
|
|
15487
15893
|
return true;
|
|
@@ -15491,13 +15897,21 @@ async function removeClaimOwnedBy(path, token, deadline = 0) {
|
|
|
15491
15897
|
}
|
|
15492
15898
|
const moved = await readClaim(movedPath);
|
|
15493
15899
|
if (moved?.owner.token !== token) {
|
|
15900
|
+
debugPolicyFailure("remove.moved-verify", "owner-missing-or-token-mismatch");
|
|
15494
15901
|
try {
|
|
15495
15902
|
await rename(movedPath, path);
|
|
15496
|
-
} catch {
|
|
15903
|
+
} catch (error) {
|
|
15904
|
+
debugPolicyFailure("remove.restore-rename", "native-error", error);
|
|
15497
15905
|
}
|
|
15498
15906
|
return false;
|
|
15499
15907
|
}
|
|
15500
|
-
|
|
15908
|
+
try {
|
|
15909
|
+
await rm8(movedPath, { force: true, recursive: true });
|
|
15910
|
+
} catch (error) {
|
|
15911
|
+
debugPolicyFailure("remove.rm", "native-error", error);
|
|
15912
|
+
throw error;
|
|
15913
|
+
}
|
|
15914
|
+
await removeClaimEndpoint(path, token);
|
|
15501
15915
|
return true;
|
|
15502
15916
|
}
|
|
15503
15917
|
function gcBatch(names) {
|
|
@@ -15512,7 +15926,7 @@ function gcBatch(names) {
|
|
|
15512
15926
|
return batch;
|
|
15513
15927
|
}
|
|
15514
15928
|
async function cleanDeadClaim(directory, name, budget) {
|
|
15515
|
-
const path =
|
|
15929
|
+
const path = join20(directory, name);
|
|
15516
15930
|
const published = name.includes(".lock-v4.claim-");
|
|
15517
15931
|
if (published) {
|
|
15518
15932
|
const entry = await lstat4(path).catch(() => void 0);
|
|
@@ -15536,7 +15950,7 @@ async function cleanDeadPolicyArtifacts(directory, budget) {
|
|
|
15536
15950
|
return;
|
|
15537
15951
|
}
|
|
15538
15952
|
for (const name of gcBatch(names)) {
|
|
15539
|
-
if (budget.signal?.aborted === true ||
|
|
15953
|
+
if (budget.signal?.aborted === true || performance.now() >= (budget.deadline ?? Infinity)) {
|
|
15540
15954
|
return;
|
|
15541
15955
|
}
|
|
15542
15956
|
await cleanDeadClaim(directory, name, budget);
|
|
@@ -15548,6 +15962,8 @@ var init_browser_execution_claim_storage = __esm({
|
|
|
15548
15962
|
"use strict";
|
|
15549
15963
|
init_process_identity();
|
|
15550
15964
|
init_process_errors();
|
|
15965
|
+
init_browser_execution_claim_endpoint();
|
|
15966
|
+
init_browser_execution_policy_debug();
|
|
15551
15967
|
init_browser_execution_claim_codec();
|
|
15552
15968
|
POLICY_LOCK_WAIT_MS = 1e3;
|
|
15553
15969
|
LOCK_OWNER_FILE = "owner.json";
|
|
@@ -15560,7 +15976,7 @@ var init_browser_execution_claim_storage = __esm({
|
|
|
15560
15976
|
// dist/extensions/agent-browser/lib/browser-execution-claims.js
|
|
15561
15977
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
15562
15978
|
import { lstat as lstat5, mkdir as mkdir4, rename as rename2, rm as rm9, writeFile as writeFile2 } from "node:fs/promises";
|
|
15563
|
-
import { join as
|
|
15979
|
+
import { join as join21 } from "node:path";
|
|
15564
15980
|
function claimPrecedes(left, right) {
|
|
15565
15981
|
if (left.ticket === null) {
|
|
15566
15982
|
return true;
|
|
@@ -15585,45 +16001,55 @@ function relevantPredecessor(claim, ownClaim) {
|
|
|
15585
16001
|
const sessions = claim.owner.sessionNames;
|
|
15586
16002
|
return ownSessions === null || sessions === null || ownSessions.some((session) => sessions.includes(session));
|
|
15587
16003
|
}
|
|
15588
|
-
async function
|
|
16004
|
+
async function blockingPredecessor(claim, ownClaim, budget) {
|
|
15589
16005
|
if (!relevantPredecessor(claim, ownClaim) || await hasPublishedLaterTicket(claim, ownClaim)) {
|
|
15590
|
-
return
|
|
16006
|
+
return void 0;
|
|
16007
|
+
}
|
|
16008
|
+
if (!await claimStillExists(claim.path)) {
|
|
16009
|
+
return void 0;
|
|
15591
16010
|
}
|
|
15592
16011
|
const alive = await ownerAlive(claim.owner, budget);
|
|
15593
16012
|
if (alive === false) {
|
|
15594
16013
|
await removeClaimOwnedBy(claim.path, claim.owner.token);
|
|
15595
|
-
return
|
|
16014
|
+
return void 0;
|
|
15596
16015
|
}
|
|
15597
16016
|
if (!await claimStillExists(claim.path)) {
|
|
15598
|
-
return
|
|
16017
|
+
return void 0;
|
|
15599
16018
|
}
|
|
15600
|
-
return
|
|
16019
|
+
return await hasPublishedLaterTicket(claim, ownClaim) ? void 0 : { claim, ownerConfirmed: alive === true };
|
|
15601
16020
|
}
|
|
15602
16021
|
async function claimStillExists(path) {
|
|
15603
16022
|
try {
|
|
15604
16023
|
await lstat5(path);
|
|
15605
16024
|
return true;
|
|
15606
16025
|
} catch (error) {
|
|
15607
|
-
|
|
16026
|
+
const code = getErrorCode(error);
|
|
16027
|
+
if (code !== "ENOENT") {
|
|
16028
|
+
debugPolicyFailure("acquire.predecessor-stat", "presence-unresolved", error);
|
|
16029
|
+
}
|
|
16030
|
+
return code !== "ENOENT";
|
|
15608
16031
|
}
|
|
15609
16032
|
}
|
|
15610
|
-
async function
|
|
16033
|
+
async function firstBlockingPredecessor(claims, own, budget) {
|
|
15611
16034
|
for (const claim of claims) {
|
|
15612
|
-
|
|
15613
|
-
|
|
16035
|
+
const blocking = await blockingPredecessor(claim, own, budget);
|
|
16036
|
+
if (blocking) {
|
|
16037
|
+
return blocking;
|
|
15614
16038
|
}
|
|
15615
16039
|
}
|
|
15616
|
-
return
|
|
16040
|
+
return void 0;
|
|
15617
16041
|
}
|
|
15618
16042
|
async function prepareClaim(identity, budget) {
|
|
15619
16043
|
const directory = getCoordinationDirectory(process.platform);
|
|
15620
16044
|
if (!await ensureCoordinationDirectory(directory, process.platform)) {
|
|
16045
|
+
debugPolicyFailure("acquire.prepare", "directory-unavailable");
|
|
15621
16046
|
return void 0;
|
|
15622
16047
|
}
|
|
15623
16048
|
const basePath = getBrowserExecutionLockPath(identity);
|
|
15624
16049
|
const token = randomUUID7();
|
|
15625
16050
|
const startIdentity = await readProcessStartIdentity(process.pid, process.platform, budget);
|
|
15626
16051
|
if (startIdentity === void 0 || startIdentity.length === 0) {
|
|
16052
|
+
debugPolicyFailure("acquire.prepare", "start-identity-unavailable");
|
|
15627
16053
|
return void 0;
|
|
15628
16054
|
}
|
|
15629
16055
|
const owner = {
|
|
@@ -15635,6 +16061,7 @@ async function prepareClaim(identity, budget) {
|
|
|
15635
16061
|
};
|
|
15636
16062
|
const content = JSON.stringify(owner);
|
|
15637
16063
|
if (Buffer.byteLength(content) > POLICY_LOCK_MAX_BYTES) {
|
|
16064
|
+
debugPolicyFailure("acquire.prepare", "owner-too-large");
|
|
15638
16065
|
return void 0;
|
|
15639
16066
|
}
|
|
15640
16067
|
return {
|
|
@@ -15646,59 +16073,164 @@ async function prepareClaim(identity, budget) {
|
|
|
15646
16073
|
path: `${basePath}.claim-${token}`
|
|
15647
16074
|
};
|
|
15648
16075
|
}
|
|
15649
|
-
|
|
15650
|
-
|
|
15651
|
-
|
|
15652
|
-
|
|
15653
|
-
|
|
15654
|
-
|
|
15655
|
-
}
|
|
15656
|
-
|
|
16076
|
+
function publicationRetryAvailable(budget) {
|
|
16077
|
+
return budget.deadline !== void 0 && budget.signal?.aborted !== true && performance.now() < budget.deadline;
|
|
16078
|
+
}
|
|
16079
|
+
function candidateMatchesPreparedClaim(candidate, claim) {
|
|
16080
|
+
if (!candidate || candidate.ticket !== null) {
|
|
16081
|
+
return false;
|
|
16082
|
+
}
|
|
16083
|
+
const { owner } = candidate;
|
|
16084
|
+
const expected = claim.owner;
|
|
16085
|
+
const sessions = owner.sessionNames;
|
|
16086
|
+
const expectedSessions = expected.sessionNames;
|
|
16087
|
+
const identityFields = ["token", "pid", "startIdentity", "version"];
|
|
16088
|
+
return identityFields.every((field) => owner[field] === expected[field]) && (expectedSessions === null ? sessions === null : sessions !== null && sessions.length === expectedSessions.length && sessions.every((session, index) => session === expectedSessions[index]));
|
|
16089
|
+
}
|
|
16090
|
+
async function publishCandidate(claim, budget) {
|
|
16091
|
+
while (true) {
|
|
16092
|
+
try {
|
|
16093
|
+
await rename2(claim.candidatePath, claim.path);
|
|
16094
|
+
return true;
|
|
16095
|
+
} catch (error) {
|
|
16096
|
+
if (process.platform !== "win32" || getErrorCode(error) !== "EPERM" || !publicationRetryAvailable(budget)) {
|
|
16097
|
+
throw error;
|
|
16098
|
+
}
|
|
16099
|
+
await waitForRetry(budget.signal);
|
|
16100
|
+
if (!publicationRetryAvailable(budget)) {
|
|
16101
|
+
throw error;
|
|
16102
|
+
}
|
|
16103
|
+
const candidate = await readClaim(claim.candidatePath);
|
|
16104
|
+
if (!candidateMatchesPreparedClaim(candidate, claim)) {
|
|
16105
|
+
debugPolicyFailure("publish.verify", "candidate-unconfirmed", error);
|
|
16106
|
+
return false;
|
|
16107
|
+
}
|
|
16108
|
+
if (!publicationRetryAvailable(budget)) {
|
|
16109
|
+
throw error;
|
|
16110
|
+
}
|
|
16111
|
+
}
|
|
16112
|
+
}
|
|
16113
|
+
}
|
|
16114
|
+
async function publishClaim(claim, budget) {
|
|
16115
|
+
let stage = "publish.mkdir";
|
|
16116
|
+
try {
|
|
16117
|
+
await mkdir4(claim.candidatePath, { mode: 448 });
|
|
16118
|
+
stage = "publish.owner-write";
|
|
16119
|
+
await writeFile2(join21(claim.candidatePath, LOCK_OWNER_FILE), claim.content, {
|
|
16120
|
+
encoding: "utf8",
|
|
16121
|
+
flag: "wx",
|
|
16122
|
+
mode: 384
|
|
16123
|
+
});
|
|
16124
|
+
stage = "publish.rename";
|
|
16125
|
+
return await publishCandidate(claim, budget);
|
|
16126
|
+
} catch (error) {
|
|
16127
|
+
debugPolicyFailure(stage, "native-error", error);
|
|
16128
|
+
throw error;
|
|
16129
|
+
}
|
|
15657
16130
|
}
|
|
15658
16131
|
async function publishTicket(claim) {
|
|
15659
16132
|
const claims = await readClaims(claim.basePath);
|
|
15660
16133
|
if (!claims) {
|
|
16134
|
+
debugPolicyFailure("ticket.scan", "claims-unavailable");
|
|
15661
16135
|
return void 0;
|
|
15662
16136
|
}
|
|
15663
16137
|
const maxTicket = claims.reduce((max, entry) => entry.ticket === null ? max : Math.max(max, entry.ticket), 0);
|
|
15664
16138
|
if (!Number.isSafeInteger(maxTicket + 1)) {
|
|
16139
|
+
debugPolicyFailure("ticket.number", "unsafe-ticket-number");
|
|
15665
16140
|
return void 0;
|
|
15666
16141
|
}
|
|
15667
16142
|
const ticket = { ticket: maxTicket + 1, token: claim.owner.token, version: 4 };
|
|
15668
|
-
const candidate =
|
|
15669
|
-
|
|
15670
|
-
|
|
16143
|
+
const candidate = join21(claim.path, `.ticket-${claim.owner.token}.tmp`);
|
|
16144
|
+
let stage = "ticket.write";
|
|
16145
|
+
try {
|
|
16146
|
+
await writeFile2(candidate, JSON.stringify(ticket), {
|
|
16147
|
+
encoding: "utf8",
|
|
16148
|
+
flag: "wx",
|
|
16149
|
+
mode: 384
|
|
16150
|
+
});
|
|
16151
|
+
stage = "ticket.rename";
|
|
16152
|
+
await rename2(candidate, join21(claim.path, LOCK_TICKET_FILE));
|
|
16153
|
+
} catch (error) {
|
|
16154
|
+
debugPolicyFailure(stage, "native-error", error);
|
|
16155
|
+
throw error;
|
|
16156
|
+
}
|
|
15671
16157
|
return ticket.ticket;
|
|
15672
16158
|
}
|
|
15673
16159
|
function acquisitionCancelled(budget) {
|
|
15674
16160
|
return budget.signal?.aborted === true;
|
|
15675
16161
|
}
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
|
|
15685
|
-
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
16162
|
+
function createPredecessorWait() {
|
|
16163
|
+
let subscription;
|
|
16164
|
+
const attempted = /* @__PURE__ */ new Set();
|
|
16165
|
+
const close = () => {
|
|
16166
|
+
subscription?.close();
|
|
16167
|
+
subscription = void 0;
|
|
16168
|
+
};
|
|
16169
|
+
return {
|
|
16170
|
+
close,
|
|
16171
|
+
wait: async (blocking, budget, deadline) => {
|
|
16172
|
+
const { token } = blocking.claim.owner;
|
|
16173
|
+
if (subscription?.token === token && subscription.connected()) {
|
|
16174
|
+
await subscription.wait(budget.signal, deadline);
|
|
16175
|
+
return;
|
|
16176
|
+
}
|
|
16177
|
+
close();
|
|
16178
|
+
if (blocking.ownerConfirmed && blocking.claim.ticket !== null && !attempted.has(token)) {
|
|
16179
|
+
attempted.add(token);
|
|
16180
|
+
subscription = await subscribeClaimEndpoint(blocking.claim.path, token, budget.signal, deadline);
|
|
16181
|
+
return;
|
|
16182
|
+
}
|
|
16183
|
+
await waitForRetry(budget.signal);
|
|
15689
16184
|
}
|
|
15690
|
-
|
|
15691
|
-
|
|
16185
|
+
};
|
|
16186
|
+
}
|
|
16187
|
+
async function waitForTurn(claim, ticket, budget, deadline) {
|
|
16188
|
+
const predecessorWait = createPredecessorWait();
|
|
16189
|
+
try {
|
|
16190
|
+
while (budget.signal?.aborted !== true) {
|
|
16191
|
+
const claims = await readClaims(claim.basePath);
|
|
16192
|
+
if (!claims) {
|
|
16193
|
+
debugPolicyFailure("acquire.wait-scan", "claims-unavailable");
|
|
16194
|
+
return false;
|
|
16195
|
+
}
|
|
16196
|
+
const own = claims.find((entry) => entry.owner.token === claim.owner.token);
|
|
16197
|
+
if (!own || own.ticket !== ticket) {
|
|
16198
|
+
debugPolicyFailure("acquire.own-claim", !own ? "missing" : "ticket-mismatch");
|
|
16199
|
+
return false;
|
|
16200
|
+
}
|
|
16201
|
+
const blocking = await firstBlockingPredecessor(claims, own, budget);
|
|
16202
|
+
if (!blocking) {
|
|
16203
|
+
return await acquireTurn(claim, budget);
|
|
16204
|
+
}
|
|
16205
|
+
if (performance.now() >= deadline) {
|
|
16206
|
+
debugPolicyFailure("acquire.wait", "deadline");
|
|
16207
|
+
return false;
|
|
16208
|
+
}
|
|
16209
|
+
await predecessorWait.wait(blocking, budget, deadline);
|
|
15692
16210
|
}
|
|
15693
|
-
|
|
16211
|
+
debugPolicyFailure("acquire.wait", "cancelled");
|
|
16212
|
+
return false;
|
|
16213
|
+
} finally {
|
|
16214
|
+
predecessorWait.close();
|
|
15694
16215
|
}
|
|
15695
|
-
|
|
16216
|
+
}
|
|
16217
|
+
async function acquireTurn(claim, budget) {
|
|
16218
|
+
await cleanDeadPolicyArtifacts(claim.directory, budget);
|
|
16219
|
+
const cancelled = acquisitionCancelled(budget);
|
|
16220
|
+
if (cancelled) {
|
|
16221
|
+
debugPolicyFailure("acquire.turn", "cancelled");
|
|
16222
|
+
}
|
|
16223
|
+
return !cancelled;
|
|
15696
16224
|
}
|
|
15697
16225
|
function acquisitionDeadline(options) {
|
|
15698
|
-
return options.deadline ??
|
|
16226
|
+
return options.deadline ?? performance.now() + (options.timeoutMs ?? POLICY_LOCK_WAIT_MS);
|
|
15699
16227
|
}
|
|
15700
|
-
|
|
15701
|
-
|
|
16228
|
+
function acquireExecutionClaim(options) {
|
|
16229
|
+
return policyDebugEnabled ? withPolicyDebugAttempt(() => acquireClaim(options)) : acquireClaim(options);
|
|
16230
|
+
}
|
|
16231
|
+
async function acquireClaim(options) {
|
|
16232
|
+
if (acquisitionCancelled(options)) {
|
|
16233
|
+
debugPolicyFailure("acquire.begin", "cancelled");
|
|
15702
16234
|
return void 0;
|
|
15703
16235
|
}
|
|
15704
16236
|
const deadline = acquisitionDeadline(options);
|
|
@@ -15712,41 +16244,68 @@ async function acquireExecutionClaim(options) {
|
|
|
15712
16244
|
}
|
|
15713
16245
|
let published = false;
|
|
15714
16246
|
let acquired = false;
|
|
16247
|
+
let cleanupCandidate = true;
|
|
16248
|
+
let endpoint;
|
|
15715
16249
|
try {
|
|
15716
|
-
await publishClaim(claim)
|
|
16250
|
+
if (!await publishClaim(claim, budget)) {
|
|
16251
|
+
cleanupCandidate = false;
|
|
16252
|
+
return void 0;
|
|
16253
|
+
}
|
|
15717
16254
|
published = true;
|
|
16255
|
+
endpoint = openClaimEndpoint(claim.path, claim.owner.token);
|
|
15718
16256
|
const ticket = await publishTicket(claim);
|
|
15719
16257
|
if (ticket === void 0 || !await waitForTurn(claim, ticket, budget, deadline)) {
|
|
15720
16258
|
return void 0;
|
|
15721
16259
|
}
|
|
15722
16260
|
acquired = true;
|
|
15723
16261
|
return {
|
|
15724
|
-
release: async () =>
|
|
15725
|
-
await removeClaimOwnedBy(claim.path, claim.owner.token, Date.now() + POLICY_LOCK_WAIT_MS);
|
|
15726
|
-
}
|
|
16262
|
+
release: policyDebugPhase("release", async () => removeOwnClaim(claim, endpoint, "release.complete"))
|
|
15727
16263
|
};
|
|
15728
|
-
} catch {
|
|
16264
|
+
} catch (error) {
|
|
16265
|
+
debugPolicyFailure("acquire.complete", "native-error", error);
|
|
15729
16266
|
return void 0;
|
|
15730
16267
|
} finally {
|
|
15731
|
-
await
|
|
16268
|
+
await cleanupUnpublishedCandidate(claim, cleanupCandidate);
|
|
15732
16269
|
if (published && !acquired) {
|
|
15733
|
-
await
|
|
16270
|
+
await removeOwnClaim(claim, endpoint, "cleanup.complete");
|
|
15734
16271
|
}
|
|
15735
16272
|
}
|
|
15736
16273
|
}
|
|
16274
|
+
async function removeOwnClaim(claim, endpoint, stage) {
|
|
16275
|
+
try {
|
|
16276
|
+
const removed = await removeClaimOwnedBy(claim.path, claim.owner.token, performance.now() + POLICY_LOCK_WAIT_MS);
|
|
16277
|
+
debugRemovalResult(removed, stage);
|
|
16278
|
+
} finally {
|
|
16279
|
+
endpoint?.close();
|
|
16280
|
+
}
|
|
16281
|
+
}
|
|
16282
|
+
async function cleanupUnpublishedCandidate(claim, permitted) {
|
|
16283
|
+
if (permitted) {
|
|
16284
|
+
await rm9(claim.candidatePath, { force: true, recursive: true }).catch((error) => {
|
|
16285
|
+
debugPolicyFailure("cleanup.candidate-rm", "native-error", error);
|
|
16286
|
+
});
|
|
16287
|
+
}
|
|
16288
|
+
}
|
|
16289
|
+
function debugRemovalResult(removed, stage) {
|
|
16290
|
+
if (!removed) {
|
|
16291
|
+
debugPolicyFailure(stage, "claim-not-removed");
|
|
16292
|
+
}
|
|
16293
|
+
}
|
|
15737
16294
|
var init_browser_execution_claims = __esm({
|
|
15738
16295
|
"dist/extensions/agent-browser/lib/browser-execution-claims.js"() {
|
|
15739
16296
|
"use strict";
|
|
15740
16297
|
init_process_errors();
|
|
16298
|
+
init_browser_execution_policy_debug();
|
|
15741
16299
|
init_process_identity();
|
|
15742
16300
|
init_browser_execution_claim_codec();
|
|
15743
16301
|
init_browser_execution_identity();
|
|
16302
|
+
init_browser_execution_claim_endpoint();
|
|
15744
16303
|
init_browser_execution_claim_storage();
|
|
15745
16304
|
}
|
|
15746
16305
|
});
|
|
15747
16306
|
|
|
15748
16307
|
// dist/extensions/agent-browser/lib/managed-session-policy-lock.js
|
|
15749
|
-
import { AsyncLocalStorage as
|
|
16308
|
+
import { AsyncLocalStorage as AsyncLocalStorage8 } from "node:async_hooks";
|
|
15750
16309
|
function groupExecutionIdentities(identities) {
|
|
15751
16310
|
if (identities.length === 0) {
|
|
15752
16311
|
throw new Error("Browser execution coordination requires at least one identity.");
|
|
@@ -15821,10 +16380,10 @@ async function withBrowserExecutionLocks(options, run) {
|
|
|
15821
16380
|
const signals = [controller.signal, options.signal, parent?.signal].filter((signal2) => signal2 !== void 0);
|
|
15822
16381
|
const signal = AbortSignal.any(signals);
|
|
15823
16382
|
const expire = () => controller.abort(new DOMException("Browser execution deadline exceeded.", "TimeoutError"));
|
|
15824
|
-
const remaining = options.deadline -
|
|
16383
|
+
const remaining = options.deadline - performance.now();
|
|
15825
16384
|
const timer = setTimeout(expire, Math.max(0, Math.min(remaining, 2147483647)));
|
|
15826
16385
|
const checkBudget = () => {
|
|
15827
|
-
if (
|
|
16386
|
+
if (performance.now() >= options.deadline) {
|
|
15828
16387
|
expire();
|
|
15829
16388
|
}
|
|
15830
16389
|
signal.throwIfAborted();
|
|
@@ -15900,7 +16459,7 @@ var init_managed_session_policy_lock = __esm({
|
|
|
15900
16459
|
init_browser_execution_claims();
|
|
15901
16460
|
init_browser_execution_identity();
|
|
15902
16461
|
init_browser_execution_identity();
|
|
15903
|
-
executionScope = new
|
|
16462
|
+
executionScope = new AsyncLocalStorage8();
|
|
15904
16463
|
}
|
|
15905
16464
|
});
|
|
15906
16465
|
|
|
@@ -15913,13 +16472,31 @@ function getRunningHeadedAutosavePolicyChangeError(recordedInterval, closeComman
|
|
|
15913
16472
|
function getHeadedManagedAutosaveEnv(interval) {
|
|
15914
16473
|
return interval !== void 0 ? { AGENT_BROWSER_AUTOSAVE_INTERVAL_MS: interval } : void 0;
|
|
15915
16474
|
}
|
|
16475
|
+
function isDaemonGeneration(value) {
|
|
16476
|
+
return isRecord(value) && typeof value.pid === "number" && Number.isSafeInteger(value.pid) && value.pid > 0 && typeof value.start === "string" && value.start !== "" && typeof value.socketDir === "string";
|
|
16477
|
+
}
|
|
16478
|
+
function managedSessionDaemonGenerationsMatch(recorded, current) {
|
|
16479
|
+
if (recorded === void 0 || current === void 0) {
|
|
16480
|
+
return void 0;
|
|
16481
|
+
}
|
|
16482
|
+
try {
|
|
16483
|
+
const previous = JSON.parse(recorded);
|
|
16484
|
+
const observed = JSON.parse(current);
|
|
16485
|
+
if (!isDaemonGeneration(previous) || !isDaemonGeneration(observed)) {
|
|
16486
|
+
return void 0;
|
|
16487
|
+
}
|
|
16488
|
+
return previous.pid !== observed.pid || previous.socketDir !== observed.socketDir ? false : processStartIdentitiesMatch(previous.start, observed.start);
|
|
16489
|
+
} catch {
|
|
16490
|
+
return void 0;
|
|
16491
|
+
}
|
|
16492
|
+
}
|
|
15916
16493
|
async function readDaemonGeneration(runtime, options) {
|
|
15917
16494
|
if (options.includeGeneration !== true || typeof runtime.backgroundPid !== "number" || !Number.isSafeInteger(runtime.backgroundPid) || runtime.backgroundPid <= 0 || typeof runtime.socketDir !== "string" || runtime.browserLaunched === false) {
|
|
15918
16495
|
return void 0;
|
|
15919
16496
|
}
|
|
15920
16497
|
const start = await readProcessStartIdentity(runtime.backgroundPid, process.platform, {
|
|
15921
16498
|
signal: options.signal,
|
|
15922
|
-
deadline:
|
|
16499
|
+
deadline: performance.now() + (options.timeoutMs ?? 5e3)
|
|
15923
16500
|
});
|
|
15924
16501
|
return start !== void 0 && start !== "" ? JSON.stringify({
|
|
15925
16502
|
pid: runtime.backgroundPid,
|
|
@@ -16089,17 +16666,17 @@ async function closeUnderPolicy(options, lifecycle) {
|
|
|
16089
16666
|
async function closeWithDeadline(options) {
|
|
16090
16667
|
const controller = new AbortController();
|
|
16091
16668
|
let phase = "policy coordination";
|
|
16092
|
-
let phaseStartedAt =
|
|
16669
|
+
let phaseStartedAt = performance.now();
|
|
16093
16670
|
let timeoutError2;
|
|
16094
16671
|
const timer = setTimeout(() => {
|
|
16095
|
-
timeoutError2 = `Managed-session cleanup timed out after ${options.timeoutMs} ms during ${phase} (${
|
|
16672
|
+
timeoutError2 = `Managed-session cleanup timed out after ${options.timeoutMs} ms during ${phase} (${Math.round(performance.now() - phaseStartedAt)} ms in this phase).`;
|
|
16096
16673
|
controller.abort();
|
|
16097
16674
|
}, options.timeoutMs);
|
|
16098
16675
|
const lifecycle = {
|
|
16099
16676
|
signal: controller.signal,
|
|
16100
16677
|
enterPhase: (nextPhase) => {
|
|
16101
16678
|
phase = nextPhase;
|
|
16102
|
-
phaseStartedAt =
|
|
16679
|
+
phaseStartedAt = performance.now();
|
|
16103
16680
|
},
|
|
16104
16681
|
clearTimer: () => {
|
|
16105
16682
|
clearTimeout(timer);
|
|
@@ -16205,7 +16782,7 @@ function reconcileDaemonReceipt(context2, daemon, receipt) {
|
|
|
16205
16782
|
if (daemon.status !== "active" || receipt === void 0 || context2.restoreState.hasDaemonRestoreKey(context2.sessionName, context2.namespace)) {
|
|
16206
16783
|
return;
|
|
16207
16784
|
}
|
|
16208
|
-
if (daemon.generation ===
|
|
16785
|
+
if (managedSessionDaemonGenerationsMatch(receipt.generation, daemon.generation) === true && daemon.restoreKey === receipt.restoreKey) {
|
|
16209
16786
|
context2.restoreState.recordDaemonRestoreKey(context2.sessionName, context2.namespace, daemon.restoreKey, daemon.generation);
|
|
16210
16787
|
} else {
|
|
16211
16788
|
context2.restoreState.forgetDaemonRestoreKey(context2.sessionName, context2.namespace);
|
|
@@ -16403,7 +16980,7 @@ var init_branch = __esm({
|
|
|
16403
16980
|
// dist/extensions/agent-browser/lib/electron/discovery-evidence.js
|
|
16404
16981
|
import { constants as fsConstants } from "node:fs";
|
|
16405
16982
|
import { access as access2, readdir as readdir7, realpath as realpath2, stat as stat9 } from "node:fs/promises";
|
|
16406
|
-
import { basename as basename6, dirname as
|
|
16983
|
+
import { basename as basename6, dirname as dirname13, extname as extname4, join as join22 } from "node:path";
|
|
16407
16984
|
async function isDirectory(path) {
|
|
16408
16985
|
try {
|
|
16409
16986
|
return (await stat9(path)).isDirectory();
|
|
@@ -16445,19 +17022,19 @@ async function directoryContainsChromePak(directory) {
|
|
|
16445
17022
|
}
|
|
16446
17023
|
}
|
|
16447
17024
|
async function hasElectronAppPayload(resourcesDirectory) {
|
|
16448
|
-
return await pathExists(
|
|
17025
|
+
return await pathExists(join22(resourcesDirectory, "app.asar")) || await pathExists(join22(resourcesDirectory, "default_app.asar")) || await isDirectory(join22(resourcesDirectory, "app"));
|
|
16449
17026
|
}
|
|
16450
17027
|
async function hasLinuxElectronEvidence(executablePath) {
|
|
16451
17028
|
const resolved = await resolveRealPath(executablePath);
|
|
16452
17029
|
if (!await isExecutableFile(resolved)) {
|
|
16453
17030
|
return false;
|
|
16454
17031
|
}
|
|
16455
|
-
const directory =
|
|
17032
|
+
const directory = dirname13(resolved);
|
|
16456
17033
|
if (!await directoryContainsChromePak(directory)) {
|
|
16457
17034
|
return false;
|
|
16458
17035
|
}
|
|
16459
|
-
for (const base of [directory,
|
|
16460
|
-
if (await hasElectronAppPayload(
|
|
17036
|
+
for (const base of [directory, dirname13(directory)]) {
|
|
17037
|
+
if (await hasElectronAppPayload(join22(base, "resources"))) {
|
|
16461
17038
|
return true;
|
|
16462
17039
|
}
|
|
16463
17040
|
}
|
|
@@ -16468,9 +17045,9 @@ async function inspectWin32Executable(executablePath) {
|
|
|
16468
17045
|
if (!await isExecutableFile(resolved)) {
|
|
16469
17046
|
return void 0;
|
|
16470
17047
|
}
|
|
16471
|
-
const directory =
|
|
16472
|
-
const hasAppPayload = await hasElectronAppPayload(
|
|
16473
|
-
const hasPak = await directoryContainsChromePak(directory) || await pathExists(
|
|
17048
|
+
const directory = dirname13(resolved);
|
|
17049
|
+
const hasAppPayload = await hasElectronAppPayload(join22(directory, "resources"));
|
|
17050
|
+
const hasPak = await directoryContainsChromePak(directory) || await pathExists(join22(directory, "resources.pak"));
|
|
16474
17051
|
if (!hasAppPayload || !hasPak) {
|
|
16475
17052
|
return void 0;
|
|
16476
17053
|
}
|
|
@@ -16488,8 +17065,8 @@ var init_discovery_evidence = __esm({
|
|
|
16488
17065
|
});
|
|
16489
17066
|
|
|
16490
17067
|
// dist/extensions/agent-browser/lib/electron/discovery-darwin.js
|
|
16491
|
-
import { readdir as readdir8, readFile as
|
|
16492
|
-
import { basename as basename7, join as
|
|
17068
|
+
import { readdir as readdir8, readFile as readFile8 } from "node:fs/promises";
|
|
17069
|
+
import { basename as basename7, join as join23 } from "node:path";
|
|
16493
17070
|
function readPlistString(plist, key) {
|
|
16494
17071
|
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
16495
17072
|
const match = new RegExp(`<key>\\s*${escapedKey}\\s*</key>\\s*<string>([\\s\\S]*?)</string>`, "i").exec(plist);
|
|
@@ -16497,7 +17074,7 @@ function readPlistString(plist, key) {
|
|
|
16497
17074
|
}
|
|
16498
17075
|
async function readMacInfoPlist(appPath) {
|
|
16499
17076
|
try {
|
|
16500
|
-
const plist = await
|
|
17077
|
+
const plist = await readFile8(join23(appPath, "Contents", "Info.plist"), "utf8");
|
|
16501
17078
|
return {
|
|
16502
17079
|
CFBundleDisplayName: readPlistString(plist, "CFBundleDisplayName") ?? "",
|
|
16503
17080
|
CFBundleExecutable: readPlistString(plist, "CFBundleExecutable") ?? "",
|
|
@@ -16509,15 +17086,15 @@ async function readMacInfoPlist(appPath) {
|
|
|
16509
17086
|
}
|
|
16510
17087
|
}
|
|
16511
17088
|
async function resolveMacExecutablePath(appPath, executableName, fallbackName) {
|
|
16512
|
-
const directory =
|
|
17089
|
+
const directory = join23(appPath, "Contents", "MacOS");
|
|
16513
17090
|
if (executableName !== void 0 && executableName.trim().length > 0) {
|
|
16514
|
-
const path =
|
|
17091
|
+
const path = join23(directory, executableName);
|
|
16515
17092
|
return await pathExists(path) ? path : void 0;
|
|
16516
17093
|
}
|
|
16517
17094
|
try {
|
|
16518
17095
|
const entries = await readdir8(directory, { withFileTypes: true });
|
|
16519
17096
|
const candidate = entries.find((entry) => entry.isFile() && entry.name === fallbackName) ?? entries.find((entry) => entry.isFile());
|
|
16520
|
-
return candidate ?
|
|
17097
|
+
return candidate ? join23(directory, candidate.name) : void 0;
|
|
16521
17098
|
} catch {
|
|
16522
17099
|
return void 0;
|
|
16523
17100
|
}
|
|
@@ -16526,11 +17103,11 @@ function firstNonempty(values) {
|
|
|
16526
17103
|
return values.find((value) => value !== void 0 && value.length > 0);
|
|
16527
17104
|
}
|
|
16528
17105
|
async function inspectDarwinApp(appPath) {
|
|
16529
|
-
const framework =
|
|
17106
|
+
const framework = join23(appPath, "Contents", "Frameworks", "Electron Framework.framework");
|
|
16530
17107
|
if (!await isDirectory(framework)) {
|
|
16531
17108
|
return void 0;
|
|
16532
17109
|
}
|
|
16533
|
-
if (!await hasElectronAppPayload(
|
|
17110
|
+
if (!await hasElectronAppPayload(join23(appPath, "Contents", "Resources"))) {
|
|
16534
17111
|
return void 0;
|
|
16535
17112
|
}
|
|
16536
17113
|
const info = await readMacInfoPlist(appPath);
|
|
@@ -16561,7 +17138,7 @@ async function inspectDirectory(directory) {
|
|
|
16561
17138
|
continue;
|
|
16562
17139
|
}
|
|
16563
17140
|
try {
|
|
16564
|
-
const app = await inspectDarwinApp(
|
|
17141
|
+
const app = await inspectDarwinApp(join23(directory, entry.name));
|
|
16565
17142
|
if (app) {
|
|
16566
17143
|
apps.push(app);
|
|
16567
17144
|
}
|
|
@@ -16726,7 +17303,7 @@ var init_discovery_desktop = __esm({
|
|
|
16726
17303
|
|
|
16727
17304
|
// dist/extensions/agent-browser/lib/electron/discovery-packages.js
|
|
16728
17305
|
import { readdir as readdir9 } from "node:fs/promises";
|
|
16729
|
-
import { basename as basename9, extname as extname5, isAbsolute as isAbsolute6, join as
|
|
17306
|
+
import { basename as basename9, extname as extname5, isAbsolute as isAbsolute6, join as join24, relative, resolve as resolve9 } from "node:path";
|
|
16730
17307
|
function pathIsWithin(path, parent) {
|
|
16731
17308
|
const relativePath = relative(resolve9(parent), resolve9(path));
|
|
16732
17309
|
return relativePath.length === 0 || !relativePath.startsWith("..") && !isAbsolute6(relativePath);
|
|
@@ -16739,7 +17316,7 @@ async function findExecutableInPath(command, pathEnv) {
|
|
|
16739
17316
|
if (directory.length === 0) {
|
|
16740
17317
|
continue;
|
|
16741
17318
|
}
|
|
16742
|
-
const candidate =
|
|
17319
|
+
const candidate = join24(directory, command);
|
|
16743
17320
|
if (await isFile(candidate)) {
|
|
16744
17321
|
return candidate;
|
|
16745
17322
|
}
|
|
@@ -16750,7 +17327,7 @@ async function resolveSnapExecutable(commandPath, entry, locations) {
|
|
|
16750
17327
|
const commandName = basename9(commandPath);
|
|
16751
17328
|
const names = [commandName, commandName.split(".")[0] ?? "", entry.desktopId.split(".")[0] ?? ""];
|
|
16752
17329
|
for (const snapName of new Set(names.filter((name) => name.length > 0))) {
|
|
16753
|
-
const root =
|
|
17330
|
+
const root = join24(locations.snapMountDirectory, snapName, "current");
|
|
16754
17331
|
const candidate = await new ElectronBinarySearch([
|
|
16755
17332
|
commandName,
|
|
16756
17333
|
commandName.split(".").at(-1) ?? commandName
|
|
@@ -16783,7 +17360,7 @@ function getFlatpakCommandName(tokens) {
|
|
|
16783
17360
|
return void 0;
|
|
16784
17361
|
}
|
|
16785
17362
|
function getFlatpakRoots(entry, locations) {
|
|
16786
|
-
const userExport =
|
|
17363
|
+
const userExport = join24(locations.homeDir, ".local", "share", "flatpak", "exports", "share", "applications");
|
|
16787
17364
|
if (pathIsWithin(entry.filePath, userExport)) {
|
|
16788
17365
|
return [locations.flatpakUserAppDirectory, locations.flatpakSystemAppDirectory];
|
|
16789
17366
|
}
|
|
@@ -16796,7 +17373,7 @@ async function resolveFlatpakExecutable(tokens, entry, locations) {
|
|
|
16796
17373
|
const appId = getFlatpakAppId(tokens, entry.desktopId);
|
|
16797
17374
|
const commandName = getFlatpakCommandName(tokens);
|
|
16798
17375
|
for (const root of getFlatpakRoots(entry, locations)) {
|
|
16799
|
-
const candidate = await new ElectronBinarySearch(commandName === void 0 ? [] : [commandName]).find(
|
|
17376
|
+
const candidate = await new ElectronBinarySearch(commandName === void 0 ? [] : [commandName]).find(join24(root, appId, "current", "active", "files"));
|
|
16800
17377
|
if (candidate !== void 0) {
|
|
16801
17378
|
return candidate;
|
|
16802
17379
|
}
|
|
@@ -16866,7 +17443,7 @@ var init_discovery_packages = __esm({
|
|
|
16866
17443
|
return void 0;
|
|
16867
17444
|
}
|
|
16868
17445
|
async inspectEntry(directory, entry, depth) {
|
|
16869
|
-
const path =
|
|
17446
|
+
const path = join24(directory, entry.name);
|
|
16870
17447
|
if (entry.isDirectory()) {
|
|
16871
17448
|
return this.visit(path, depth + 1);
|
|
16872
17449
|
}
|
|
@@ -16884,8 +17461,8 @@ var init_discovery_packages = __esm({
|
|
|
16884
17461
|
});
|
|
16885
17462
|
|
|
16886
17463
|
// dist/extensions/agent-browser/lib/electron/discovery-linux.js
|
|
16887
|
-
import { readdir as readdir10, readFile as
|
|
16888
|
-
import { basename as basename10, extname as extname6, isAbsolute as isAbsolute7, join as
|
|
17464
|
+
import { readdir as readdir10, readFile as readFile9 } from "node:fs/promises";
|
|
17465
|
+
import { basename as basename10, extname as extname6, isAbsolute as isAbsolute7, join as join25 } from "node:path";
|
|
16889
17466
|
async function resolveLinuxExecutable(entry, locations) {
|
|
16890
17467
|
const tokens = stripEnvLauncher(tokenizeDesktopExec(entry.exec));
|
|
16891
17468
|
const token = tokens.at(0);
|
|
@@ -16909,7 +17486,7 @@ async function resolveLinuxExecutable(entry, locations) {
|
|
|
16909
17486
|
async function inspectLinuxDesktopFile(filePath, locations) {
|
|
16910
17487
|
let text3;
|
|
16911
17488
|
try {
|
|
16912
|
-
text3 = await
|
|
17489
|
+
text3 = await readFile9(filePath, "utf8");
|
|
16913
17490
|
} catch {
|
|
16914
17491
|
return void 0;
|
|
16915
17492
|
}
|
|
@@ -16945,7 +17522,7 @@ async function inspectDirectory2(directory, locations) {
|
|
|
16945
17522
|
continue;
|
|
16946
17523
|
}
|
|
16947
17524
|
try {
|
|
16948
|
-
const app = await inspectLinuxDesktopFile(
|
|
17525
|
+
const app = await inspectLinuxDesktopFile(join25(directory, entry.name), locations);
|
|
16949
17526
|
if (app) {
|
|
16950
17527
|
apps.push(app);
|
|
16951
17528
|
}
|
|
@@ -16987,7 +17564,7 @@ __export(discovery_exports, {
|
|
|
16987
17564
|
inspectElectronExecutablePath: () => inspectElectronExecutablePath
|
|
16988
17565
|
});
|
|
16989
17566
|
import { homedir as homedir3 } from "node:os";
|
|
16990
|
-
import { basename as basename11, join as
|
|
17567
|
+
import { basename as basename11, join as join26, resolve as resolve10, sep } from "node:path";
|
|
16991
17568
|
function normalizeSensitivityValue(value) {
|
|
16992
17569
|
const normalized = value?.trim().replace(/[_./\\-]+/g, " ").replace(/\s+/g, " ");
|
|
16993
17570
|
return normalized === void 0 || normalized.length === 0 ? void 0 : normalized;
|
|
@@ -17021,17 +17598,17 @@ function normalizeMaxResults(value) {
|
|
|
17021
17598
|
}
|
|
17022
17599
|
function linuxDesktopDirectories(locations, homeDir) {
|
|
17023
17600
|
return locations?.linuxDesktopDirectories ?? [
|
|
17024
|
-
|
|
17601
|
+
join26(homeDir, ".local", "share", "applications"),
|
|
17025
17602
|
"/usr/share/applications",
|
|
17026
17603
|
"/var/lib/snapd/desktop/applications",
|
|
17027
|
-
|
|
17604
|
+
join26(homeDir, ".local", "share", "flatpak", "exports", "share", "applications"),
|
|
17028
17605
|
"/var/lib/flatpak/exports/share/applications"
|
|
17029
17606
|
];
|
|
17030
17607
|
}
|
|
17031
17608
|
function resolvePackageLocations(locations, homeDir) {
|
|
17032
17609
|
return {
|
|
17033
17610
|
flatpakSystemAppDirectory: locations?.flatpakSystemAppDirectory ?? "/var/lib/flatpak/app",
|
|
17034
|
-
flatpakUserAppDirectory: locations?.flatpakUserAppDirectory ??
|
|
17611
|
+
flatpakUserAppDirectory: locations?.flatpakUserAppDirectory ?? join26(homeDir, ".local", "share", "flatpak", "app"),
|
|
17035
17612
|
snapBinDirectory: locations?.snapBinDirectory ?? "/snap/bin",
|
|
17036
17613
|
snapMountDirectory: locations?.snapMountDirectory ?? "/snap"
|
|
17037
17614
|
};
|
|
@@ -17043,7 +17620,7 @@ function resolveLocations(locations) {
|
|
|
17043
17620
|
homeDir,
|
|
17044
17621
|
darwinApplicationDirectories: locations?.darwinApplicationDirectories ?? [
|
|
17045
17622
|
"/Applications",
|
|
17046
|
-
|
|
17623
|
+
join26(homeDir, "Applications")
|
|
17047
17624
|
],
|
|
17048
17625
|
linuxDesktopDirectories: linuxDesktopDirectories(locations, homeDir),
|
|
17049
17626
|
pathEnv: locations?.pathEnv ?? process.env.PATH ?? ""
|
|
@@ -17083,12 +17660,12 @@ function sortApps(apps) {
|
|
|
17083
17660
|
});
|
|
17084
17661
|
}
|
|
17085
17662
|
function findMacAppBundleAncestor(path) {
|
|
17086
|
-
const parts = resolve10(path).split(
|
|
17663
|
+
const parts = resolve10(path).split(sep);
|
|
17087
17664
|
const index = parts.findIndex((part) => part.endsWith(".app"));
|
|
17088
17665
|
if (index < 0) {
|
|
17089
17666
|
return void 0;
|
|
17090
17667
|
}
|
|
17091
|
-
const ancestor = parts.slice(0, index + 1).join(
|
|
17668
|
+
const ancestor = parts.slice(0, index + 1).join(sep);
|
|
17092
17669
|
return ancestor.length > 0 ? ancestor : "/";
|
|
17093
17670
|
}
|
|
17094
17671
|
async function inspectElectronExecutablePath(executablePath, platform = process.platform) {
|
|
@@ -19466,7 +20043,7 @@ var init_timeout_diagnostics = __esm({
|
|
|
19466
20043
|
// dist/extensions/agent-browser/lib/executable-path.js
|
|
19467
20044
|
import { constants as fsConstants2 } from "node:fs";
|
|
19468
20045
|
import { access as access3, stat as stat11 } from "node:fs/promises";
|
|
19469
|
-
import { delimiter, join as
|
|
20046
|
+
import { delimiter, join as join27 } from "node:path";
|
|
19470
20047
|
async function isExecutableFile2(candidate) {
|
|
19471
20048
|
try {
|
|
19472
20049
|
await access3(candidate, fsConstants2.X_OK);
|
|
@@ -19477,7 +20054,7 @@ async function isExecutableFile2(candidate) {
|
|
|
19477
20054
|
}
|
|
19478
20055
|
async function executableExistsOnPath(command) {
|
|
19479
20056
|
const extensions = process.platform === "win32" ? (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean) : [""];
|
|
19480
|
-
const candidates = (process.env.PATH ?? "").split(delimiter).filter(Boolean).flatMap((directory) => extensions.map((extension) =>
|
|
20057
|
+
const candidates = (process.env.PATH ?? "").split(delimiter).filter(Boolean).flatMap((directory) => extensions.map((extension) => join27(directory, `${command}${extension}`)));
|
|
19481
20058
|
for (const candidate of candidates) {
|
|
19482
20059
|
if (await isExecutableFile2(candidate)) {
|
|
19483
20060
|
return true;
|
|
@@ -20102,6 +20679,7 @@ function nativeObservationDetails(options, lifecycle, browserWindow) {
|
|
|
20102
20679
|
recordingRecovery: options.presentation.recordingRecovery,
|
|
20103
20680
|
readConfirmation: options.presentation.readConfirmation,
|
|
20104
20681
|
exitCode: options.processResult.exitCode,
|
|
20682
|
+
exitSignal: options.processResult.exitSignal,
|
|
20105
20683
|
parseError: options.plainTextInspection ? void 0 : options.parseError,
|
|
20106
20684
|
stderr: options.processResult.stderr,
|
|
20107
20685
|
stdout: options.plainTextInspection ? options.inspectionText ?? "" : void 0,
|
|
@@ -22745,11 +23323,12 @@ var init_batch_redaction = __esm({
|
|
|
22745
23323
|
function createStepIdentity(item, index) {
|
|
22746
23324
|
const command = isStringArray2(item.command) ? item.command : void 0;
|
|
22747
23325
|
const redactedCommand = command ? redactInvocationArgs(command) : void 0;
|
|
23326
|
+
const visibleCommand = hasModelFacingArgRedaction(redactedCommand) ? redactedCommand : command;
|
|
22748
23327
|
return {
|
|
22749
23328
|
command,
|
|
22750
23329
|
redactedCommand,
|
|
22751
|
-
index,
|
|
22752
|
-
commandText: formatBatchStepCommand(
|
|
23330
|
+
index: item.index ?? index,
|
|
23331
|
+
commandText: formatBatchStepCommand(item.index === void 0 ? visibleCommand : void 0, item.index ?? index),
|
|
22753
23332
|
lifecycle: extractAgentBrowserLifecycle(item.result)
|
|
22754
23333
|
};
|
|
22755
23334
|
}
|
|
@@ -22930,12 +23509,16 @@ async function buildBatchStepPresentation(options) {
|
|
|
22930
23509
|
const identity = createStepIdentity(options.item, options.index);
|
|
22931
23510
|
const scope = { namespace: options.namespace, sessionName: options.sessionName };
|
|
22932
23511
|
if (options.item.success === false && identity.command?.[0] !== "record") {
|
|
22933
|
-
return
|
|
23512
|
+
return {
|
|
23513
|
+
...buildFailedStep(options.item, identity, scope),
|
|
23514
|
+
nativeIndex: options.item.index
|
|
23515
|
+
};
|
|
22934
23516
|
}
|
|
22935
23517
|
const request = buildNestedRequest(options, identity.command);
|
|
22936
23518
|
const presentation = await options.buildNestedToolPresentation(request);
|
|
22937
23519
|
return {
|
|
22938
23520
|
details: buildStepDetails(presentation, identity, request.commandInfo, scope),
|
|
23521
|
+
nativeIndex: options.item.index,
|
|
22939
23522
|
presentation
|
|
22940
23523
|
};
|
|
22941
23524
|
}
|
|
@@ -23121,6 +23704,9 @@ function scanTypingRun(steps, start) {
|
|
|
23121
23704
|
return typedStepCount >= 2 ? { nextIndex: index, typedCharCount, delayMs } : void 0;
|
|
23122
23705
|
}
|
|
23123
23706
|
function getTypingStart(steps, index) {
|
|
23707
|
+
if (steps.at(index)?.nativeIndex !== void 0) {
|
|
23708
|
+
return void 0;
|
|
23709
|
+
}
|
|
23124
23710
|
const details = steps.at(index)?.details;
|
|
23125
23711
|
if (!details || !details.success) {
|
|
23126
23712
|
return void 0;
|
|
@@ -23243,13 +23829,20 @@ function formatBatchStatusText(steps, status, modelVisible) {
|
|
|
23243
23829
|
].filter((line) => line !== void 0).join("\n\n");
|
|
23244
23830
|
}
|
|
23245
23831
|
function serializeBatchData(steps) {
|
|
23246
|
-
return steps.map(({ details }) => details.success ? {
|
|
23247
|
-
|
|
23832
|
+
return steps.map(({ details, nativeIndex }) => details.success ? {
|
|
23833
|
+
...batchResultIdentity(details.command, nativeIndex),
|
|
23834
|
+
result: details.data,
|
|
23835
|
+
success: true
|
|
23836
|
+
} : {
|
|
23837
|
+
...batchResultIdentity(details.command, nativeIndex),
|
|
23248
23838
|
error: details.text,
|
|
23249
23839
|
...details.command?.[0] === "record" ? { result: details.data } : {},
|
|
23250
23840
|
success: false
|
|
23251
23841
|
});
|
|
23252
23842
|
}
|
|
23843
|
+
function batchResultIdentity(command, index) {
|
|
23844
|
+
return index === void 0 ? { command } : { index };
|
|
23845
|
+
}
|
|
23253
23846
|
function formatBatchChangeText(observed, unverified) {
|
|
23254
23847
|
if (observed === 0) {
|
|
23255
23848
|
return `batch \u2192 ${unverified} action${unverified === 1 ? "" : "s"} dispatched \u2192 application change unverified`;
|
|
@@ -23289,7 +23882,7 @@ var init_batch_summary = __esm({
|
|
|
23289
23882
|
|
|
23290
23883
|
// dist/extensions/agent-browser/lib/results/presentation/batch.js
|
|
23291
23884
|
function isAgentBrowserBatchResultArray(value) {
|
|
23292
|
-
return Array.isArray(value) && value.every((row) => isRecord(row) && (row.command === void 0 || isStringArray2(row.command)) && (row.success === void 0 || typeof row.success === "boolean"));
|
|
23885
|
+
return Array.isArray(value) && value.every((row) => isRecord(row) && (row.command === void 0 || isStringArray2(row.command)) && (row.index === void 0 || typeof row.index === "number" && Number.isSafeInteger(row.index) && row.index >= 0) && (row.success === void 0 || typeof row.success === "boolean"));
|
|
23293
23886
|
}
|
|
23294
23887
|
async function collectPresentedSteps(options) {
|
|
23295
23888
|
const steps = [];
|
|
@@ -23678,6 +24271,12 @@ function stateShowText(data) {
|
|
|
23678
24271
|
}
|
|
23679
24272
|
return lines.join("\n");
|
|
23680
24273
|
}
|
|
24274
|
+
function stateLoadText(data) {
|
|
24275
|
+
const loaded = `State loaded: ${redactModelFacingText(getStringField(data, "path") ?? getStringField(data, "name") ?? "ok")}`;
|
|
24276
|
+
const skipped = (getArrayField(data, "skippedOrigins") ?? []).filter((origin) => typeof origin === "string");
|
|
24277
|
+
return skipped.length === 0 ? loaded : `${loaded}
|
|
24278
|
+
Skipped storage for origins (page did not stay on that origin): ${redactModelFacingText(skipped.join(", "))}`;
|
|
24279
|
+
}
|
|
23681
24280
|
function formatStateText(data, subcommand) {
|
|
23682
24281
|
if (subcommand === "show") {
|
|
23683
24282
|
return stateShowText(data);
|
|
@@ -23687,7 +24286,7 @@ function formatStateText(data, subcommand) {
|
|
|
23687
24286
|
return states.length === 0 ? "No saved states." : states.map(stateLine).join("\n");
|
|
23688
24287
|
}
|
|
23689
24288
|
if (data.loaded === true) {
|
|
23690
|
-
return
|
|
24289
|
+
return stateLoadText(data);
|
|
23691
24290
|
}
|
|
23692
24291
|
return data.cleared === true || data.clear === true ? "State cleared." : void 0;
|
|
23693
24292
|
}
|
|
@@ -23730,6 +24329,7 @@ var init_diagnostic_identity = __esm({
|
|
|
23730
24329
|
"compatibilityStatus",
|
|
23731
24330
|
"restoreKey",
|
|
23732
24331
|
"restoreStatus",
|
|
24332
|
+
"restoreSkippedOrigins",
|
|
23733
24333
|
"restoreLoadedPath",
|
|
23734
24334
|
"restoreValidationPending",
|
|
23735
24335
|
"restoreSave",
|
|
@@ -25214,7 +25814,7 @@ function redactBatchSpillData(data) {
|
|
|
25214
25814
|
const command = isStringArray2(row.command) ? row.command : void 0;
|
|
25215
25815
|
return {
|
|
25216
25816
|
...row,
|
|
25217
|
-
command: command ? redactInvocationArgs(command) :
|
|
25817
|
+
command: row.index === void 0 && command ? redactInvocationArgs(command) : void 0,
|
|
25218
25818
|
error: row.error === void 0 ? void 0 : redactBatchStepErrorData(command, row.error),
|
|
25219
25819
|
result: row.result === void 0 ? void 0 : redactPresentationData(parseCommandInfo(command ?? []), row.result)
|
|
25220
25820
|
};
|
|
@@ -25734,7 +26334,7 @@ var init_prepare_failure = __esm({
|
|
|
25734
26334
|
});
|
|
25735
26335
|
|
|
25736
26336
|
// dist/extensions/agent-browser/lib/electron/launch-monitor.js
|
|
25737
|
-
import { readFile as
|
|
26337
|
+
import { readFile as readFile12 } from "node:fs/promises";
|
|
25738
26338
|
function isElectronLaunchAborted(signal) {
|
|
25739
26339
|
return signal?.aborted ?? false;
|
|
25740
26340
|
}
|
|
@@ -25759,7 +26359,7 @@ function activePortReadError(error) {
|
|
|
25759
26359
|
async function readDevToolsActivePort(userDataDir) {
|
|
25760
26360
|
const path = `${userDataDir}/DevToolsActivePort`;
|
|
25761
26361
|
try {
|
|
25762
|
-
const text3 = await
|
|
26362
|
+
const text3 = await readFile12(path, "utf8");
|
|
25763
26363
|
const port = Number(text3.split(/\r?\n/)[0].trim());
|
|
25764
26364
|
const valid = Number.isSafeInteger(port) && port > 0 && port <= 65535;
|
|
25765
26365
|
return {
|
|
@@ -25774,7 +26374,7 @@ async function readDevToolsActivePort(userDataDir) {
|
|
|
25774
26374
|
}
|
|
25775
26375
|
async function pollDevToolsActivePort(options) {
|
|
25776
26376
|
let devToolsActivePort;
|
|
25777
|
-
while (
|
|
26377
|
+
while (performance.now() <= options.deadlineMs) {
|
|
25778
26378
|
if (isElectronLaunchAborted(options.signal)) {
|
|
25779
26379
|
return { devToolsActivePort, failure: "aborted" };
|
|
25780
26380
|
}
|
|
@@ -25798,7 +26398,7 @@ async function pollDevToolsActivePort(options) {
|
|
|
25798
26398
|
return { devToolsActivePort, failure: "timeout" };
|
|
25799
26399
|
}
|
|
25800
26400
|
async function pollCdpMetadata(port, deadlineMs, signal) {
|
|
25801
|
-
while (
|
|
26401
|
+
while (performance.now() <= deadlineMs) {
|
|
25802
26402
|
if (isElectronLaunchAborted(signal)) {
|
|
25803
26403
|
return { aborted: true };
|
|
25804
26404
|
}
|
|
@@ -25830,7 +26430,7 @@ var init_launch_monitor = __esm({
|
|
|
25830
26430
|
// dist/extensions/agent-browser/lib/electron/launch-process.js
|
|
25831
26431
|
import { spawn as spawn3 } from "node:child_process";
|
|
25832
26432
|
import { open as open5 } from "node:fs/promises";
|
|
25833
|
-
import { dirname as
|
|
26433
|
+
import { dirname as dirname17, join as join31 } from "node:path";
|
|
25834
26434
|
async function closeOutputHandle(file) {
|
|
25835
26435
|
try {
|
|
25836
26436
|
await file.close();
|
|
@@ -25925,11 +26525,11 @@ var init_launch_process = __esm({
|
|
|
25925
26525
|
async spawn(executablePath, args, signal) {
|
|
25926
26526
|
const handles = [];
|
|
25927
26527
|
try {
|
|
25928
|
-
handles.push(await open5(
|
|
25929
|
-
handles.push(await open5(
|
|
26528
|
+
handles.push(await open5(join31(this.userDataDir, "stdout.log"), "wx", 384));
|
|
26529
|
+
handles.push(await open5(join31(this.userDataDir, "stderr.log"), "wx", 384));
|
|
25930
26530
|
signal?.throwIfAborted();
|
|
25931
26531
|
this.process = spawn3(executablePath, args, {
|
|
25932
|
-
cwd:
|
|
26532
|
+
cwd: dirname17(executablePath),
|
|
25933
26533
|
detached: process.platform !== "win32",
|
|
25934
26534
|
stdio: ["ignore", handles[0].fd, handles[1].fd]
|
|
25935
26535
|
});
|
|
@@ -25960,12 +26560,13 @@ var init_launch_process = __esm({
|
|
|
25960
26560
|
return isRecord(error) && error.code === "EPERM";
|
|
25961
26561
|
}
|
|
25962
26562
|
}
|
|
26563
|
+
/** Waits for exit until deadlineMs, a performance.now() timestamp unaffected by wall-clock steps. */
|
|
25963
26564
|
async waitForExit(deadlineMs) {
|
|
25964
26565
|
const child = this.process;
|
|
25965
26566
|
if (child === void 0) {
|
|
25966
26567
|
return true;
|
|
25967
26568
|
}
|
|
25968
|
-
while (
|
|
26569
|
+
while (performance.now() <= deadlineMs) {
|
|
25969
26570
|
if (child.exitCode !== null || child.signalCode !== null) {
|
|
25970
26571
|
return true;
|
|
25971
26572
|
}
|
|
@@ -25990,14 +26591,14 @@ var init_launch_process = __esm({
|
|
|
25990
26591
|
if (terminateError !== void 0) {
|
|
25991
26592
|
return terminateError;
|
|
25992
26593
|
}
|
|
25993
|
-
if (await this.waitForExit(
|
|
26594
|
+
if (await this.waitForExit(performance.now() + 1e3)) {
|
|
25994
26595
|
return void 0;
|
|
25995
26596
|
}
|
|
25996
26597
|
const killError = this.signalChild("SIGKILL");
|
|
25997
26598
|
if (killError !== void 0) {
|
|
25998
26599
|
return killError;
|
|
25999
26600
|
}
|
|
26000
|
-
if (await this.waitForExit(
|
|
26601
|
+
if (await this.waitForExit(performance.now() + 1e3)) {
|
|
26001
26602
|
return void 0;
|
|
26002
26603
|
}
|
|
26003
26604
|
return `PID ${child.pid} remained alive after failed Electron launch cleanup.`;
|
|
@@ -26007,8 +26608,8 @@ var init_launch_process = __esm({
|
|
|
26007
26608
|
return { evidence: {}, lines: [] };
|
|
26008
26609
|
}
|
|
26009
26610
|
const [stdout, stderr] = await Promise.all([
|
|
26010
|
-
readOutputTail(
|
|
26011
|
-
readOutputTail(
|
|
26611
|
+
readOutputTail(join31(this.userDataDir, "stdout.log")),
|
|
26612
|
+
readOutputTail(join31(this.userDataDir, "stderr.log"))
|
|
26012
26613
|
]);
|
|
26013
26614
|
return {
|
|
26014
26615
|
evidence: {
|
|
@@ -26186,7 +26787,7 @@ async function launchElectronApp(options) {
|
|
|
26186
26787
|
};
|
|
26187
26788
|
}
|
|
26188
26789
|
const timeoutMs = normalizeTimeoutMs(options.timeoutMs);
|
|
26189
|
-
const startedAtMs =
|
|
26790
|
+
const startedAtMs = performance.now();
|
|
26190
26791
|
const userDataDir = await createSecureTempDirectory(ELECTRON_PROFILE_DIR_PREFIX);
|
|
26191
26792
|
if (isElectronLaunchAborted(options.signal)) {
|
|
26192
26793
|
return abortedProfileResult(userDataDir, options, target);
|
|
@@ -26231,7 +26832,7 @@ var init_launch = __esm({
|
|
|
26231
26832
|
diagnostics(observation2) {
|
|
26232
26833
|
return {
|
|
26233
26834
|
...observation2,
|
|
26234
|
-
elapsedMs: Math.max(0,
|
|
26835
|
+
elapsedMs: Math.round(Math.max(0, performance.now() - this.startedAtMs)),
|
|
26235
26836
|
exitCode: this.process.exitCode,
|
|
26236
26837
|
exitSignal: this.process.exitSignal,
|
|
26237
26838
|
outputCaptured: this.process.outputCaptured,
|
|
@@ -26365,7 +26966,7 @@ var init_launch = __esm({
|
|
|
26365
26966
|
|
|
26366
26967
|
// dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js
|
|
26367
26968
|
import { copyFile, mkdir as mkdir6 } from "node:fs/promises";
|
|
26368
|
-
import { dirname as
|
|
26969
|
+
import { dirname as dirname18, resolve as resolve16 } from "node:path";
|
|
26369
26970
|
function getArtifactParentPathTokenIndex(commandTokens) {
|
|
26370
26971
|
if (commandTokens[0] === "download" && commandTokens.length >= 3) {
|
|
26371
26972
|
return 2;
|
|
@@ -26390,7 +26991,7 @@ async function ensureArtifactParentDirectory(commandTokens, cwd) {
|
|
|
26390
26991
|
if (requestedPath === void 0 || requestedPath === "") {
|
|
26391
26992
|
return;
|
|
26392
26993
|
}
|
|
26393
|
-
await mkdir6(
|
|
26994
|
+
await mkdir6(dirname18(resolve16(cwd, requestedPath)), { recursive: true });
|
|
26394
26995
|
}
|
|
26395
26996
|
function screenshotPathIndex(commandTokens, batchStep) {
|
|
26396
26997
|
if (batchStep) {
|
|
@@ -26407,7 +27008,7 @@ async function normalizeScreenshotPathInTokens(commandTokens, cwd, batchStep = f
|
|
|
26407
27008
|
}
|
|
26408
27009
|
const requestedPath = commandTokens[pathIndex];
|
|
26409
27010
|
const absolutePath = resolve16(cwd, requestedPath);
|
|
26410
|
-
await mkdir6(
|
|
27011
|
+
await mkdir6(dirname18(absolutePath), { recursive: true });
|
|
26411
27012
|
const tokens = [...commandTokens];
|
|
26412
27013
|
tokens[pathIndex] = absolutePath;
|
|
26413
27014
|
const terminatorIndex = batchStep ? -1 : tokens.indexOf("--");
|
|
@@ -26502,7 +27103,7 @@ async function repairScreenshotData(options) {
|
|
|
26502
27103
|
if (reportedAbsolutePath !== void 0 && reportedAbsolutePath !== request.absolutePath) {
|
|
26503
27104
|
tempPath = reportedAbsolutePath;
|
|
26504
27105
|
if (status === "missing" && await pathExists(reportedAbsolutePath)) {
|
|
26505
|
-
await mkdir6(
|
|
27106
|
+
await mkdir6(dirname18(request.absolutePath), { recursive: true });
|
|
26506
27107
|
await copyFile(reportedAbsolutePath, request.absolutePath);
|
|
26507
27108
|
status = "repaired-from-temp";
|
|
26508
27109
|
}
|
|
@@ -26834,6 +27435,31 @@ var init_prepare_session_plan = __esm({
|
|
|
26834
27435
|
});
|
|
26835
27436
|
|
|
26836
27437
|
// dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js
|
|
27438
|
+
async function notCallerOwned() {
|
|
27439
|
+
return false;
|
|
27440
|
+
}
|
|
27441
|
+
function observeCallerDaemonInactive(facts, { plan, session }) {
|
|
27442
|
+
if (session.ownedManagedSession) {
|
|
27443
|
+
return notCallerOwned;
|
|
27444
|
+
}
|
|
27445
|
+
let observation2;
|
|
27446
|
+
const observe = async () => {
|
|
27447
|
+
const initial = facts.initialDaemonObservation;
|
|
27448
|
+
if (initial?.identity === getAgentBrowserSessionIdentityKey(plan.sessionName ?? "", plan.namespace)) {
|
|
27449
|
+
return initial.daemon.status === "inactive";
|
|
27450
|
+
}
|
|
27451
|
+
return plan.sessionName !== void 0 && (await inspectManagedSessionDaemon({
|
|
27452
|
+
cwd: facts.cwd,
|
|
27453
|
+
signal: facts.signal,
|
|
27454
|
+
sessionName: plan.sessionName,
|
|
27455
|
+
namespace: plan.namespace
|
|
27456
|
+
})).status === "inactive";
|
|
27457
|
+
};
|
|
27458
|
+
return () => {
|
|
27459
|
+
observation2 ??= observe();
|
|
27460
|
+
return observation2;
|
|
27461
|
+
};
|
|
27462
|
+
}
|
|
26837
27463
|
function daemonReuseError(plan, session, policy) {
|
|
26838
27464
|
if (policy.error !== void 0 && policy.error !== "") {
|
|
26839
27465
|
return policy.error;
|
|
@@ -26865,7 +27491,12 @@ async function prepareDaemonPolicy(process2, electronLaunchRecord, planning) {
|
|
|
26865
27491
|
const { plan, session } = planning;
|
|
26866
27492
|
const context2 = session.ownedManagedSession;
|
|
26867
27493
|
if (session.browserIndependent || planHasValidationError(plan) || !context2) {
|
|
26868
|
-
return {
|
|
27494
|
+
return {
|
|
27495
|
+
plan,
|
|
27496
|
+
session,
|
|
27497
|
+
policy: { inactive: false },
|
|
27498
|
+
callerDaemonInactive: observeCallerDaemonInactive(process2, planning)
|
|
27499
|
+
};
|
|
26869
27500
|
}
|
|
26870
27501
|
const closeCommand = isCloseCommand(plan.commandInfo.command);
|
|
26871
27502
|
const policy = await acquireOwnedManagedSessionDaemonPolicy({
|
|
@@ -26886,7 +27517,8 @@ async function prepareDaemonPolicy(process2, electronLaunchRecord, planning) {
|
|
|
26886
27517
|
inactive: policy.daemonStatus === "inactive",
|
|
26887
27518
|
generationInspection: policy.generationInspection,
|
|
26888
27519
|
cleanupOnlyReason: policy.error !== void 0 && policy.error !== "" ? policy.cleanupOnlyReason : void 0
|
|
26889
|
-
}
|
|
27520
|
+
},
|
|
27521
|
+
callerDaemonInactive: notCallerOwned
|
|
26890
27522
|
};
|
|
26891
27523
|
}
|
|
26892
27524
|
function chromeStartupEligible(facts, plan, request) {
|
|
@@ -26899,16 +27531,7 @@ async function prepareChromeStartupArgs(facts, planning, request) {
|
|
|
26899
27531
|
})) {
|
|
26900
27532
|
return void 0;
|
|
26901
27533
|
}
|
|
26902
|
-
const
|
|
26903
|
-
let inactive = policy.inactive;
|
|
26904
|
-
if (!session.ownedManagedSession) {
|
|
26905
|
-
inactive = (facts.initialDaemonObservation?.identity === getAgentBrowserSessionIdentityKey(plan.sessionName ?? "", plan.namespace) ? facts.initialDaemonObservation.daemon.status === "inactive" : void 0) ?? (plan.sessionName !== void 0 && (await inspectManagedSessionDaemon({
|
|
26906
|
-
cwd: facts.cwd,
|
|
26907
|
-
signal: facts.signal,
|
|
26908
|
-
sessionName: plan.sessionName,
|
|
26909
|
-
namespace: plan.namespace
|
|
26910
|
-
})).status === "inactive");
|
|
26911
|
-
}
|
|
27534
|
+
const inactive = planning.session.ownedManagedSession ? planning.policy.inactive : await planning.callerDaemonInactive();
|
|
26912
27535
|
return inactive || facts.configuredChromeLaunch === true ? facts.chromeStartupArgs : void 0;
|
|
26913
27536
|
}
|
|
26914
27537
|
var init_prepare_daemon = __esm({
|
|
@@ -26964,11 +27587,10 @@ async function reconcileGeneration(pageState, process2, request) {
|
|
|
26964
27587
|
owned: session.ownedManagedSession
|
|
26965
27588
|
}, request.generationInspection);
|
|
26966
27589
|
pageState.bindSnapshotGeneration(key, daemon.status === "active" ? daemon.generation : void 0);
|
|
26967
|
-
const
|
|
26968
|
-
if (
|
|
27590
|
+
const generationMatch = managedSessionDaemonGenerationsMatch(snapshot.generation, daemon.status === "active" ? daemon.generation : void 0);
|
|
27591
|
+
if (generationMatch === true) {
|
|
26969
27592
|
return { ...page, nativeGenerationChanged: false };
|
|
26970
27593
|
}
|
|
26971
|
-
const nativeGenerationChanged = generationKnown && snapshot.generation !== void 0;
|
|
26972
27594
|
const invalidation = buildPageTransitionRefSnapshotInvalidation("The native browser generation changed or could not be verified. Take a new complete snapshot before using refs, even when the URL is unchanged.");
|
|
26973
27595
|
pageState.applyRefSnapshotInvalidation({
|
|
26974
27596
|
invalidation,
|
|
@@ -26977,7 +27599,7 @@ async function reconcileGeneration(pageState, process2, request) {
|
|
|
26977
27599
|
});
|
|
26978
27600
|
return {
|
|
26979
27601
|
...page,
|
|
26980
|
-
nativeGenerationChanged,
|
|
27602
|
+
nativeGenerationChanged: generationMatch === false,
|
|
26981
27603
|
priorRefSnapshotState: void 0,
|
|
26982
27604
|
priorRefSnapshotInvalidation: invalidation
|
|
26983
27605
|
};
|
|
@@ -27034,6 +27656,7 @@ var init_prepare_page_state = __esm({
|
|
|
27034
27656
|
init_session_page_state();
|
|
27035
27657
|
init_managed_session_daemon_policy();
|
|
27036
27658
|
init_session_state();
|
|
27659
|
+
init_managed_session_daemon_inspection();
|
|
27037
27660
|
}
|
|
27038
27661
|
});
|
|
27039
27662
|
|
|
@@ -27157,7 +27780,7 @@ async function preparePageSelection(pageState, process2, hasReadConfirmation, re
|
|
|
27157
27780
|
executionPlan: request.plan,
|
|
27158
27781
|
livePageVerified: false
|
|
27159
27782
|
};
|
|
27160
|
-
if (!shouldSelectRememberedTab(request.plan, hasReadConfirmation, request)) {
|
|
27783
|
+
if (!shouldSelectRememberedTab(request.plan, hasReadConfirmation, request) || await probeWouldDropLaunchFlags(process2)) {
|
|
27161
27784
|
return base;
|
|
27162
27785
|
}
|
|
27163
27786
|
process2.signal?.throwIfAborted();
|
|
@@ -27208,6 +27831,9 @@ function verifiedLivePage(selection, url) {
|
|
|
27208
27831
|
}
|
|
27209
27832
|
};
|
|
27210
27833
|
}
|
|
27834
|
+
async function probeWouldDropLaunchFlags(process2) {
|
|
27835
|
+
return process2.preserveAttachedBrowserSession !== true && await process2.callerColdLaunch?.() === true;
|
|
27836
|
+
}
|
|
27211
27837
|
async function verifyPreparationLivePage(process2, selection, request) {
|
|
27212
27838
|
const plan = selection.executionPlan;
|
|
27213
27839
|
if (request.requirement === void 0 || request.requirement === "" || plan.sessionName === void 0 || plan.sessionName === "") {
|
|
@@ -27216,6 +27842,9 @@ async function verifyPreparationLivePage(process2, selection, request) {
|
|
|
27216
27842
|
if (process2.establishAttachedBrowserSession === true) {
|
|
27217
27843
|
return { ...selection, executionPlan: withPlanValidationError(plan, request.requirement) };
|
|
27218
27844
|
}
|
|
27845
|
+
if (await probeWouldDropLaunchFlags(process2)) {
|
|
27846
|
+
return selection;
|
|
27847
|
+
}
|
|
27219
27848
|
const url = await readLiveUrl(process2, plan);
|
|
27220
27849
|
if (url === void 0) {
|
|
27221
27850
|
return { ...selection, executionPlan: withPlanValidationError(plan, request.requirement) };
|
|
@@ -28863,9 +29492,11 @@ async function prepareNativeCommand(facts, context2, evidence) {
|
|
|
28863
29492
|
const plan = context2.semantic.selection.executionPlan;
|
|
28864
29493
|
const page = context2.semantic.selection.page;
|
|
28865
29494
|
const input = context2.input;
|
|
29495
|
+
const callerColdLaunch = !context2.session.browserIndependent && needsManagedSession(parseArgvDescriptor(plan.effectiveArgs), native.processStdin) && facts.preserveAttachedBrowserSession !== true && await facts.callerColdLaunch?.() === true;
|
|
28866
29496
|
return {
|
|
28867
29497
|
kind: "ready",
|
|
28868
29498
|
prepared: {
|
|
29499
|
+
callerColdLaunch: callerColdLaunch ? true : void 0,
|
|
28869
29500
|
compiledElectron: input.compiledElectron,
|
|
28870
29501
|
compiledJob: input.compiledJob,
|
|
28871
29502
|
compiledNetworkSourceLookup: input.compiledNetworkSourceLookup,
|
|
@@ -28914,6 +29545,8 @@ var init_prepare_command = __esm({
|
|
|
28914
29545
|
init_process();
|
|
28915
29546
|
init_runtime_redaction();
|
|
28916
29547
|
init_argv_grammar();
|
|
29548
|
+
init_argv_descriptor();
|
|
29549
|
+
init_command_policy();
|
|
28917
29550
|
init_click_dispatch();
|
|
28918
29551
|
init_diagnostics();
|
|
28919
29552
|
init_prepare_failure();
|
|
@@ -28983,6 +29616,10 @@ async function prepareCommandPhases(state, controls, context2) {
|
|
|
28983
29616
|
}
|
|
28984
29617
|
async function preparePagePhases(state, controls, planning, request) {
|
|
28985
29618
|
const { plan, session, policy } = planning;
|
|
29619
|
+
const pageControls = {
|
|
29620
|
+
...controls,
|
|
29621
|
+
callerColdLaunch: hasBrowserLaunchFlag(request.preparedArgs.args) ? planning.callerDaemonInactive : void 0
|
|
29622
|
+
};
|
|
28986
29623
|
const initial = controls.initialDaemonObservation;
|
|
28987
29624
|
const page = await preparePageState(state, controls, {
|
|
28988
29625
|
plan,
|
|
@@ -28992,7 +29629,7 @@ async function preparePagePhases(state, controls, planning, request) {
|
|
|
28992
29629
|
preserveAttachedBrowserSession: controls.preserveAttachedBrowserSession,
|
|
28993
29630
|
generationInspection: policy.generationInspection ?? (!session.ownedManagedSession && initial?.generationInspected === true && initial.identity === getAgentBrowserSessionIdentityKey(plan.sessionName ?? "", plan.namespace) ? initial.daemon : void 0)
|
|
28994
29631
|
});
|
|
28995
|
-
const selection = await preparePageSelection(state.sessionPageState,
|
|
29632
|
+
const selection = await preparePageSelection(state.sessionPageState, pageControls, session.readConfirmation !== void 0, {
|
|
28996
29633
|
...request,
|
|
28997
29634
|
plan,
|
|
28998
29635
|
page,
|
|
@@ -29001,14 +29638,14 @@ async function preparePagePhases(state, controls, planning, request) {
|
|
|
29001
29638
|
if ("earlyResult" in selection) {
|
|
29002
29639
|
return selection.earlyResult;
|
|
29003
29640
|
}
|
|
29004
|
-
const semantic = await prepareSemanticAction(
|
|
29641
|
+
const semantic = await prepareSemanticAction(pageControls, request.sessionFacts, {
|
|
29005
29642
|
hasReadConfirmation: session.readConfirmation !== void 0,
|
|
29006
29643
|
ownsSession: session.ownedManagedSession !== void 0
|
|
29007
29644
|
}, {
|
|
29008
29645
|
...request,
|
|
29009
29646
|
selection
|
|
29010
29647
|
});
|
|
29011
|
-
return prepareCommandPhases(state,
|
|
29648
|
+
return prepareCommandPhases(state, pageControls, { ...request, semantic, session, policy });
|
|
29012
29649
|
}
|
|
29013
29650
|
async function prepareRequest(identity, input, settings) {
|
|
29014
29651
|
const freshSessionName = createFreshSessionName(identity.managedSessionBaseName, identity.ephemeralSessionSeed, identity.freshSessionOrdinal + 1);
|
|
@@ -29121,6 +29758,7 @@ var init_prepare = __esm({
|
|
|
29121
29758
|
"dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js"() {
|
|
29122
29759
|
"use strict";
|
|
29123
29760
|
init_runtime();
|
|
29761
|
+
init_launch_scoped_flags();
|
|
29124
29762
|
init_page_target_validation();
|
|
29125
29763
|
init_categories();
|
|
29126
29764
|
init_process();
|
|
@@ -29242,20 +29880,20 @@ function planRecordingRecovery(options) {
|
|
|
29242
29880
|
return void 0;
|
|
29243
29881
|
}
|
|
29244
29882
|
const { batch, steps, rows } = recoverySource(options);
|
|
29245
|
-
const
|
|
29246
|
-
if (
|
|
29883
|
+
const stopPosition = steps.reduce((last, step, position) => isRecordingStop(step) && stopNeedsRecovery(options, rows?.at(position)) ? position : last, -1);
|
|
29884
|
+
if (stopPosition < 0) {
|
|
29247
29885
|
return void 0;
|
|
29248
29886
|
}
|
|
29249
29887
|
let expected = options.reservation;
|
|
29250
|
-
for (const [
|
|
29251
|
-
expected = reservationForStart(options, step, rows?.at(
|
|
29888
|
+
for (const [position, step] of steps.slice(0, stopPosition).entries()) {
|
|
29889
|
+
expected = reservationForStart(options, step, rows?.at(position)) ?? expected;
|
|
29252
29890
|
}
|
|
29253
29891
|
return {
|
|
29254
29892
|
batch,
|
|
29255
29893
|
rows,
|
|
29256
|
-
|
|
29894
|
+
stopPosition,
|
|
29257
29895
|
expected,
|
|
29258
|
-
attempt: originalAttempt(options, rows?.at(
|
|
29896
|
+
attempt: originalAttempt(options, rows?.at(stopPosition))
|
|
29259
29897
|
};
|
|
29260
29898
|
}
|
|
29261
29899
|
function receiptMatches(receipt, expected, nowMs) {
|
|
@@ -29410,7 +30048,7 @@ function classifyRecordingRecovery(evidence, plan, verified) {
|
|
|
29410
30048
|
}
|
|
29411
30049
|
function repairRecordingEnvelope(options, plan, data, verified) {
|
|
29412
30050
|
if (plan.rows) {
|
|
29413
|
-
const rows = plan.rows.map((row,
|
|
30051
|
+
const rows = plan.rows.map((row, position) => position === plan.stopPosition && isRecord(row) ? { ...row, result: data, success: verified, error: verified ? void 0 : row.error } : row);
|
|
29414
30052
|
const healed = verified && !options.processResult.timedOut && rows.every((row) => isRecord(row) && row.success === true);
|
|
29415
30053
|
return {
|
|
29416
30054
|
healed,
|
|
@@ -29523,13 +30161,13 @@ async function recoverRecordingStop(options) {
|
|
|
29523
30161
|
batch: plan.batch,
|
|
29524
30162
|
envelope: repaired.envelope,
|
|
29525
30163
|
partialBatch: plan.batch && plan.rows === void 0,
|
|
29526
|
-
|
|
30164
|
+
stopPosition: plan.stopPosition,
|
|
29527
30165
|
presentation: finishRecordingPresentation(options, presentation, evidence, recovery),
|
|
29528
30166
|
recovery
|
|
29529
30167
|
};
|
|
29530
30168
|
}
|
|
29531
30169
|
function mergeRecoveryNextActions(base, result) {
|
|
29532
|
-
const laterRecording = base.batchSteps?.slice(result.
|
|
30170
|
+
const laterRecording = base.batchSteps?.slice(result.stopPosition + 1).some((step) => step.artifacts?.some(isPendingRecordingArtifact) === true) === true;
|
|
29533
30171
|
const unrelatedFailure = base.batchFailure !== void 0 && !isRecordingStop(base.batchFailure.failedStep.command ?? []);
|
|
29534
30172
|
const nextActions = (base.nextActions ?? []).filter((action) => action.id === "stop-pending-recording" ? laterRecording : unrelatedFailure);
|
|
29535
30173
|
appendUniqueAgentBrowserNextActions(nextActions, result.presentation.nextActions);
|
|
@@ -29544,7 +30182,7 @@ function mergeRecordingRecoveryPresentation(base, result) {
|
|
|
29544
30182
|
...base,
|
|
29545
30183
|
artifacts,
|
|
29546
30184
|
artifactVerification: buildArtifactVerificationSummary(artifacts ?? []),
|
|
29547
|
-
batchSteps: base.batchSteps?.map((step) =>
|
|
30185
|
+
batchSteps: base.batchSteps?.map((step, position) => position === result.stopPosition ? {
|
|
29548
30186
|
...step,
|
|
29549
30187
|
artifacts: result.presentation.artifacts,
|
|
29550
30188
|
artifactVerification: result.presentation.artifactVerification
|
|
@@ -29583,6 +30221,10 @@ async function parseNativeOutput(draft) {
|
|
|
29583
30221
|
plainText: draft.plainTextUpgrade,
|
|
29584
30222
|
textOutput: draft.textOutput
|
|
29585
30223
|
});
|
|
30224
|
+
draft.parsed = {
|
|
30225
|
+
...draft.parsed,
|
|
30226
|
+
envelope: resolveIndexedBatchCommands(draft.parsed.envelope, draft.input.prepared.commandTokens, draft.input.prepared.runtimeToolStdin)
|
|
30227
|
+
};
|
|
29586
30228
|
observeNativeWebMcp(draft.parsed.envelope?.data);
|
|
29587
30229
|
draft.parseError = draft.parsed.parseError;
|
|
29588
30230
|
draft.recordingStopRecovery = await recoverRecordingStop({
|
|
@@ -30213,7 +30855,9 @@ function mergeObservedNavigation(draft) {
|
|
|
30213
30855
|
async function observeNavigationTarget(draft) {
|
|
30214
30856
|
resolveResultingPageState(draft);
|
|
30215
30857
|
const { prepared, cwd, signal } = draft.input;
|
|
30216
|
-
|
|
30858
|
+
const navigationRequested = navigationObservationRequested(draft);
|
|
30859
|
+
const coldTargetObservation = prepared.callerColdLaunch === true && !isOpenNavigationCommand(prepared.executionPlan.commandInfo.command);
|
|
30860
|
+
if (canObserveSuccessfulNavigation(draft) && (navigationRequested || coldTargetObservation)) {
|
|
30217
30861
|
draft.navigationSummary = await collectNavigationSummary({
|
|
30218
30862
|
cwd,
|
|
30219
30863
|
namespace: prepared.executionPlan.namespace,
|
|
@@ -30233,7 +30877,9 @@ async function observeNavigationTarget(draft) {
|
|
|
30233
30877
|
});
|
|
30234
30878
|
draft.failedTransitionReverification = draft.navigationSummary !== void 0;
|
|
30235
30879
|
}
|
|
30236
|
-
|
|
30880
|
+
if (navigationRequested || draft.failedTransitionReverification) {
|
|
30881
|
+
mergeObservedNavigation(draft);
|
|
30882
|
+
}
|
|
30237
30883
|
}
|
|
30238
30884
|
async function correctRestoredOpenTab(draft) {
|
|
30239
30885
|
const { prepared, cwd, signal } = draft.input;
|
|
@@ -30730,6 +31376,9 @@ function getTransitionInvalidation(draft) {
|
|
|
30730
31376
|
if (draft.unsettledWebMcpMutation) {
|
|
30731
31377
|
return buildPageTransitionRefSnapshotInvalidation("A detached WebMCP invocation is still pending or failed to settle and can mutate, rerender, or navigate the page, so prior snapshot refs remain invalid after URL verification. Run webmcp result or cancel, then take a fresh snapshot before using page-scoped refs.");
|
|
30732
31378
|
}
|
|
31379
|
+
if (draft.input.prepared.callerColdLaunch === true && draft.input.processResult.agentBrowserStarted) {
|
|
31380
|
+
return buildPageTransitionRefSnapshotInvalidation("The previous caller-owned browser stopped. Take a fresh complete snapshot before using page-scoped refs.");
|
|
31381
|
+
}
|
|
30733
31382
|
return observedTransitionInvalidation(draft, direct ?? planned);
|
|
30734
31383
|
}
|
|
30735
31384
|
function observedTransitionInvalidation(draft, commandInvalidation) {
|
|
@@ -31426,6 +32075,7 @@ function resolveNativeErrorText(draft) {
|
|
|
31426
32075
|
effectiveArgs: draft.input.prepared.redactedProcessArgs,
|
|
31427
32076
|
envelope: draft.presentationEnvelope,
|
|
31428
32077
|
exitCode: draft.input.processResult.exitCode,
|
|
32078
|
+
exitSignal: draft.input.processResult.exitSignal,
|
|
31429
32079
|
parseError: draft.parseError,
|
|
31430
32080
|
plainTextInspection: draft.plainTextInspection,
|
|
31431
32081
|
staleRefArgs: getStaleRefArgs(draft.input.prepared.commandTokens, draft.input.prepared.runtimeToolStdin),
|
|
@@ -31470,7 +32120,7 @@ function observeResultLaunchPolicy(draft) {
|
|
|
31470
32120
|
draft.resultHeadedManagedAutosaveInterval = resultRetainsPreparedManagedSession && !(draft.commandClosesSession && draft.succeeded) ? draft.input.prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval : void 0;
|
|
31471
32121
|
}
|
|
31472
32122
|
function classifyMalformedNativeFailure(draft) {
|
|
31473
|
-
if (draft.parseError !== void 0 && draft.parseError.length > 0 && draft.input.processResult.exitCode !== 0 &&
|
|
32123
|
+
if (draft.parseError !== void 0 && draft.parseError.length > 0 && draft.input.processResult.exitCode !== 0 && !draft.input.processResult.timedOut && !draft.input.processResult.aborted && !draft.input.processResult.spawnError) {
|
|
31474
32124
|
draft.presentation.failureCategory = "upstream-error";
|
|
31475
32125
|
}
|
|
31476
32126
|
}
|
|
@@ -32432,7 +33082,23 @@ __export(process_output_exports, {
|
|
|
32432
33082
|
processBrowserOutput: () => processBrowserOutput
|
|
32433
33083
|
});
|
|
32434
33084
|
import { rm as rm14 } from "node:fs/promises";
|
|
32435
|
-
|
|
33085
|
+
function coldLaunchOutput(input) {
|
|
33086
|
+
if (input.prepared.callerColdLaunch !== true || !input.processResult.agentBrowserStarted) {
|
|
33087
|
+
return input;
|
|
33088
|
+
}
|
|
33089
|
+
return {
|
|
33090
|
+
...input,
|
|
33091
|
+
prepared: {
|
|
33092
|
+
...input.prepared,
|
|
33093
|
+
priorSessionTabTarget: void 0,
|
|
33094
|
+
priorSessionTabTargetUnknown: true,
|
|
33095
|
+
priorRefSnapshotState: void 0,
|
|
33096
|
+
resolvedSemanticActionRefSnapshot: void 0
|
|
33097
|
+
}
|
|
33098
|
+
};
|
|
33099
|
+
}
|
|
33100
|
+
async function processBrowserOutput(invocation) {
|
|
33101
|
+
const input = coldLaunchOutput(invocation);
|
|
32436
33102
|
const ownership = captureBrowserOutputOwnership(input);
|
|
32437
33103
|
try {
|
|
32438
33104
|
const native = await observeNativeEffects(input, ownership);
|
|
@@ -32473,6 +33139,11 @@ import { open as open2, stat as stat2 } from "node:fs/promises";
|
|
|
32473
33139
|
// dist/extensions/agent-browser/lib/browser-journal-projection.js
|
|
32474
33140
|
init_parsing();
|
|
32475
33141
|
var ENVELOPE_MAX_BYTES = 16 * 1024 * 1024;
|
|
33142
|
+
var MAX_NESTING = 1024;
|
|
33143
|
+
var RESERVE_PER_BYTE = 16;
|
|
33144
|
+
var NATIVE_RECORD_BYTES = ENVELOPE_MAX_BYTES / RESERVE_PER_BYTE;
|
|
33145
|
+
var NATIVE_STRUCTURE_LIMIT = 64 * 1024;
|
|
33146
|
+
var JOURNAL_CHUNK_BYTES = 64 * 1024;
|
|
32476
33147
|
function matches(field, key) {
|
|
32477
33148
|
return field === key || field === "*" && typeof key === "number";
|
|
32478
33149
|
}
|
|
@@ -32611,7 +33282,7 @@ var JsonProjection = class {
|
|
|
32611
33282
|
}
|
|
32612
33283
|
}
|
|
32613
33284
|
startContainer(name) {
|
|
32614
|
-
if (this.stack.length >=
|
|
33285
|
+
if (this.stack.length >= MAX_NESTING) {
|
|
32615
33286
|
throw new Error("Journal JSON nesting exceeds 1024 levels.");
|
|
32616
33287
|
}
|
|
32617
33288
|
const currentPath = this.excluded() ? [] : this.path();
|
|
@@ -32676,14 +33347,110 @@ async function projectJson(input, fields, maxBytes = ENVELOPE_MAX_BYTES) {
|
|
|
32676
33347
|
consume(chain.none);
|
|
32677
33348
|
return projection.result();
|
|
32678
33349
|
}
|
|
33350
|
+
function stringEnd(bytes, open6) {
|
|
33351
|
+
for (let quote = bytes.indexOf(34, open6 + 1); quote !== -1; quote = bytes.indexOf(34, quote + 1)) {
|
|
33352
|
+
let escapes = 0;
|
|
33353
|
+
while (bytes[quote - 1 - escapes] === 92) {
|
|
33354
|
+
escapes++;
|
|
33355
|
+
}
|
|
33356
|
+
if (escapes % 2 === 0) {
|
|
33357
|
+
return quote;
|
|
33358
|
+
}
|
|
33359
|
+
}
|
|
33360
|
+
return -1;
|
|
33361
|
+
}
|
|
33362
|
+
var DEPTH_STEP = new Int8Array(256);
|
|
33363
|
+
var STRUCTURE_STEP = new Uint8Array(256);
|
|
33364
|
+
for (const byte of [91, 123]) {
|
|
33365
|
+
DEPTH_STEP[byte] = 1;
|
|
33366
|
+
STRUCTURE_STEP[byte] = 1;
|
|
33367
|
+
}
|
|
33368
|
+
for (const byte of [93, 125]) {
|
|
33369
|
+
DEPTH_STEP[byte] = -1;
|
|
33370
|
+
}
|
|
33371
|
+
for (const byte of [44, 58]) {
|
|
33372
|
+
STRUCTURE_STEP[byte] = 1;
|
|
33373
|
+
}
|
|
33374
|
+
function fitsNativeParse(bytes) {
|
|
33375
|
+
let depth = 0;
|
|
33376
|
+
let structure = 0;
|
|
33377
|
+
for (let index = 0; index < bytes.length; index++) {
|
|
33378
|
+
const byte = bytes[index];
|
|
33379
|
+
if (byte === 34) {
|
|
33380
|
+
index = stringEnd(bytes, index);
|
|
33381
|
+
if (index === -1) {
|
|
33382
|
+
return false;
|
|
33383
|
+
}
|
|
33384
|
+
continue;
|
|
33385
|
+
}
|
|
33386
|
+
depth += DEPTH_STEP[byte];
|
|
33387
|
+
structure += STRUCTURE_STEP[byte];
|
|
33388
|
+
if (depth > MAX_NESTING || structure > NATIVE_STRUCTURE_LIMIT) {
|
|
33389
|
+
return false;
|
|
33390
|
+
}
|
|
33391
|
+
}
|
|
33392
|
+
return true;
|
|
33393
|
+
}
|
|
33394
|
+
function selectValue(value, path, fields) {
|
|
33395
|
+
if (typeof value !== "object" || value === null || fields.some((field) => field.every((key, index) => matches(key, path[index])))) {
|
|
33396
|
+
return value;
|
|
33397
|
+
}
|
|
33398
|
+
if (Array.isArray(value)) {
|
|
33399
|
+
const selected2 = [];
|
|
33400
|
+
for (const [index, item] of value.entries()) {
|
|
33401
|
+
const itemPath = [...path, index];
|
|
33402
|
+
if (selectedPath(itemPath, fields)) {
|
|
33403
|
+
selected2[index] = selectValue(item, itemPath, fields);
|
|
33404
|
+
}
|
|
33405
|
+
}
|
|
33406
|
+
return selected2;
|
|
33407
|
+
}
|
|
33408
|
+
const selected = {};
|
|
33409
|
+
for (const [key, item] of Object.entries(value)) {
|
|
33410
|
+
const itemPath = [...path, key];
|
|
33411
|
+
if (selectedPath(itemPath, fields)) {
|
|
33412
|
+
Object.defineProperty(selected, key, {
|
|
33413
|
+
value: selectValue(item, itemPath, fields),
|
|
33414
|
+
writable: true,
|
|
33415
|
+
enumerable: true,
|
|
33416
|
+
configurable: true
|
|
33417
|
+
});
|
|
33418
|
+
}
|
|
33419
|
+
}
|
|
33420
|
+
return selected;
|
|
33421
|
+
}
|
|
33422
|
+
function nativeProjection(bytes, fields) {
|
|
33423
|
+
if (!fitsNativeParse(bytes)) {
|
|
33424
|
+
return void 0;
|
|
33425
|
+
}
|
|
33426
|
+
let value;
|
|
33427
|
+
try {
|
|
33428
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
33429
|
+
} catch {
|
|
33430
|
+
return void 0;
|
|
33431
|
+
}
|
|
33432
|
+
if (!isRecord(value)) {
|
|
33433
|
+
return void 0;
|
|
33434
|
+
}
|
|
33435
|
+
const selected = selectValue(value, [], fields);
|
|
33436
|
+
return isRecord(selected) ? selected : void 0;
|
|
33437
|
+
}
|
|
33438
|
+
async function* chunks(bytes) {
|
|
33439
|
+
for (let start = 0; start < bytes.length; start += JOURNAL_CHUNK_BYTES) {
|
|
33440
|
+
yield bytes.subarray(start, start + JOURNAL_CHUNK_BYTES);
|
|
33441
|
+
}
|
|
33442
|
+
}
|
|
33443
|
+
async function projectJsonBytes(bytes, fields, maxBytes = ENVELOPE_MAX_BYTES) {
|
|
33444
|
+
const native = bytes.length * RESERVE_PER_BYTE <= maxBytes ? nativeProjection(bytes, fields) : void 0;
|
|
33445
|
+
return native ?? projectJson(chunks(bytes), fields, maxBytes);
|
|
33446
|
+
}
|
|
32679
33447
|
|
|
32680
33448
|
// dist/extensions/agent-browser/lib/browser-journal-reader.js
|
|
32681
|
-
var CHUNK_BYTES = 64 * 1024;
|
|
32682
33449
|
async function* readRange(file, range) {
|
|
32683
33450
|
let position = range.offset;
|
|
32684
33451
|
const end = range.offset + range.length;
|
|
32685
33452
|
while (position < end) {
|
|
32686
|
-
const buffer = Buffer.allocUnsafe(Math.min(
|
|
33453
|
+
const buffer = Buffer.allocUnsafe(Math.min(JOURNAL_CHUNK_BYTES, end - position));
|
|
32687
33454
|
const { bytesRead } = await file.read(buffer, 0, buffer.length, position);
|
|
32688
33455
|
if (bytesRead === 0) {
|
|
32689
33456
|
throw new Error("Journal changed or truncated during read.");
|
|
@@ -32692,35 +33459,69 @@ async function* readRange(file, range) {
|
|
|
32692
33459
|
yield buffer.subarray(0, bytesRead);
|
|
32693
33460
|
}
|
|
32694
33461
|
}
|
|
33462
|
+
function hasContent(buffer, start, end) {
|
|
33463
|
+
for (let index = start; index < end; index++) {
|
|
33464
|
+
const byte = buffer[index];
|
|
33465
|
+
if (byte !== 9 && byte !== 13 && byte !== 32) {
|
|
33466
|
+
return true;
|
|
33467
|
+
}
|
|
33468
|
+
}
|
|
33469
|
+
return false;
|
|
33470
|
+
}
|
|
32695
33471
|
var JournalLineFramer = class {
|
|
32696
33472
|
start;
|
|
32697
33473
|
nonblank = false;
|
|
33474
|
+
parts = [];
|
|
33475
|
+
held = 0;
|
|
32698
33476
|
constructor(offset) {
|
|
32699
33477
|
this.start = offset;
|
|
32700
33478
|
}
|
|
32701
33479
|
*accept(buffer, position) {
|
|
32702
|
-
|
|
32703
|
-
|
|
32704
|
-
|
|
32705
|
-
|
|
32706
|
-
|
|
32707
|
-
|
|
32708
|
-
|
|
32709
|
-
|
|
32710
|
-
}
|
|
32711
|
-
|
|
33480
|
+
let index = 0;
|
|
33481
|
+
while (index < buffer.length) {
|
|
33482
|
+
const newline = buffer.indexOf(10, index);
|
|
33483
|
+
const end = newline === -1 ? buffer.length : newline;
|
|
33484
|
+
this.nonblank ||= hasContent(buffer, index, end);
|
|
33485
|
+
this.hold(buffer.subarray(index, newline === -1 ? end : end + 1));
|
|
33486
|
+
if (newline === -1) {
|
|
33487
|
+
return;
|
|
33488
|
+
}
|
|
33489
|
+
const record = this.take(position + newline + 1);
|
|
33490
|
+
if (record) {
|
|
33491
|
+
yield record;
|
|
32712
33492
|
}
|
|
33493
|
+
index = newline + 1;
|
|
32713
33494
|
}
|
|
32714
33495
|
}
|
|
32715
33496
|
final(end, sealed) {
|
|
32716
|
-
return
|
|
33497
|
+
return sealed ? this.take(end) : void 0;
|
|
33498
|
+
}
|
|
33499
|
+
hold(part) {
|
|
33500
|
+
this.held += part.length;
|
|
33501
|
+
if (this.held > NATIVE_RECORD_BYTES) {
|
|
33502
|
+
this.parts = void 0;
|
|
33503
|
+
} else {
|
|
33504
|
+
this.parts?.push(part);
|
|
33505
|
+
}
|
|
33506
|
+
}
|
|
33507
|
+
take(next) {
|
|
33508
|
+
let record;
|
|
33509
|
+
if (this.nonblank) {
|
|
33510
|
+
const range = { offset: this.start, length: next - this.start };
|
|
33511
|
+
record = this.parts ? { ...range, bytes: Buffer.concat(this.parts) } : range;
|
|
33512
|
+
}
|
|
33513
|
+
this.start = next;
|
|
33514
|
+
this.nonblank = false;
|
|
33515
|
+
this.parts = [];
|
|
33516
|
+
this.held = 0;
|
|
33517
|
+
return record;
|
|
32717
33518
|
}
|
|
32718
33519
|
};
|
|
32719
33520
|
async function* journalRanges(file, end, sealed = false, offset = 0) {
|
|
32720
33521
|
let position = offset;
|
|
32721
33522
|
const framer = new JournalLineFramer(offset);
|
|
32722
33523
|
while (position < end) {
|
|
32723
|
-
const buffer = Buffer.allocUnsafe(Math.min(
|
|
33524
|
+
const buffer = Buffer.allocUnsafe(Math.min(JOURNAL_CHUNK_BYTES, end - position));
|
|
32724
33525
|
const { bytesRead } = await file.read(buffer, 0, buffer.length, position);
|
|
32725
33526
|
if (bytesRead === 0) {
|
|
32726
33527
|
throw new Error("Journal truncated during read.");
|
|
@@ -32748,14 +33549,14 @@ var STRUCTURAL_FIELDS = [
|
|
|
32748
33549
|
["message", "details", "artifactManifest", "version"],
|
|
32749
33550
|
["message", "details", "electron", "action"]
|
|
32750
33551
|
];
|
|
32751
|
-
async function scanJournalMetadata(file, end, sealed = false) {
|
|
33552
|
+
async function scanJournalMetadata(file, end, sealed = false, offset = 0) {
|
|
32752
33553
|
const entries = [];
|
|
32753
|
-
for await (const range of journalRanges(file, end, sealed)) {
|
|
32754
|
-
const value = await projectJson(readRange(file, range), STRUCTURAL_FIELDS);
|
|
33554
|
+
for await (const range of journalRanges(file, end, sealed, offset)) {
|
|
33555
|
+
const value = range.bytes ? await projectJsonBytes(range.bytes, STRUCTURAL_FIELDS) : await projectJson(readRange(file, range), STRUCTURAL_FIELDS);
|
|
32755
33556
|
if (!value) {
|
|
32756
33557
|
throw new Error(`Expected a journal object at byte ${range.offset}.`);
|
|
32757
33558
|
}
|
|
32758
|
-
entries.push({
|
|
33559
|
+
entries.push({ offset: range.offset, length: range.length, value });
|
|
32759
33560
|
}
|
|
32760
33561
|
return entries;
|
|
32761
33562
|
}
|
|
@@ -33331,6 +34132,20 @@ var REPLAY_CUSTOM_TYPES = /* @__PURE__ */ new Set([
|
|
|
33331
34132
|
"agent-browser-recording-reservation",
|
|
33332
34133
|
"agent-browser-script-session"
|
|
33333
34134
|
]);
|
|
34135
|
+
var journalIndexes = /* @__PURE__ */ new WeakMap();
|
|
34136
|
+
function appendCompatible(previous, current) {
|
|
34137
|
+
return previous.dev === current.dev && previous.ino === current.ino && current.size >= previous.size && (current.size > previous.size || current.mtimeMs === previous.mtimeMs && current.ctimeMs === previous.ctimeMs);
|
|
34138
|
+
}
|
|
34139
|
+
async function readJournalIndex(manager, file, path, captured) {
|
|
34140
|
+
const previous = journalIndexes.get(manager);
|
|
34141
|
+
journalIndexes.delete(manager);
|
|
34142
|
+
const reusable = previous?.path === path && appendCompatible(previous.captured, captured) && previous.header === manager.getHeader();
|
|
34143
|
+
const prefix = reusable ? previous.metadata : [];
|
|
34144
|
+
const last = prefix.at(-1);
|
|
34145
|
+
const offset = last ? last.offset + last.length : 0;
|
|
34146
|
+
const suffix = reusable && captured.size === previous.captured.size ? [] : await scanJournalMetadata(file, captured.size, false, offset);
|
|
34147
|
+
return { path, header: manager.getHeader(), captured, metadata: [...prefix, ...suffix] };
|
|
34148
|
+
}
|
|
33334
34149
|
function branchEntries(entries, selectedLeaf) {
|
|
33335
34150
|
const byId = /* @__PURE__ */ new Map();
|
|
33336
34151
|
for (const entry of entries) {
|
|
@@ -33429,6 +34244,16 @@ function winningSnapshot(body, source) {
|
|
|
33429
34244
|
const value = body?.[source.root];
|
|
33430
34245
|
return isRecord(value) && isRecord(value.details) ? legacySnapshot(value.details.refSnapshot, source.id) : void 0;
|
|
33431
34246
|
}
|
|
34247
|
+
async function projectEntryBody(file, entry, fields, maxBytes) {
|
|
34248
|
+
if (entry.length > NATIVE_RECORD_BYTES) {
|
|
34249
|
+
return projectJson(readRange(file, entry), fields, maxBytes);
|
|
34250
|
+
}
|
|
34251
|
+
const parts = [];
|
|
34252
|
+
for await (const part of readRange(file, entry)) {
|
|
34253
|
+
parts.push(part);
|
|
34254
|
+
}
|
|
34255
|
+
return projectJsonBytes(Buffer.concat(parts), fields, maxBytes);
|
|
34256
|
+
}
|
|
33432
34257
|
var PublishedJournalReplay = class {
|
|
33433
34258
|
file;
|
|
33434
34259
|
ownerSessionId;
|
|
@@ -33458,7 +34283,7 @@ var PublishedJournalReplay = class {
|
|
|
33458
34283
|
this.advance(value, parent);
|
|
33459
34284
|
return;
|
|
33460
34285
|
}
|
|
33461
|
-
const body = await
|
|
34286
|
+
const body = await projectEntryBody(this.file, entry, replayFields(value, legacy), legacy ? Infinity : void 0);
|
|
33462
34287
|
const candidate = { ...value, ...body };
|
|
33463
34288
|
const record = this.normalizeRecord(candidate, parent);
|
|
33464
34289
|
this.rememberSnapshot(entry, legacy, record?.snapshot);
|
|
@@ -33502,7 +34327,7 @@ var PublishedJournalReplay = class {
|
|
|
33502
34327
|
}
|
|
33503
34328
|
const { entry, legacy } = definition;
|
|
33504
34329
|
const root = entry.value.type === "message" ? "message" : "data";
|
|
33505
|
-
const body = await
|
|
34330
|
+
const body = await projectEntryBody(this.file, entry, legacy ? [[root, "details", "refSnapshot"]] : [["data", "snapshot"]], Infinity);
|
|
33506
34331
|
const resolved = winningSnapshot(body, { root, legacy, id });
|
|
33507
34332
|
const destination = this.projected.find((candidate) => isRecord(candidate) && candidate.id === entry.value.id);
|
|
33508
34333
|
if (!isRecord(destination) || !isRecord(destination.data)) {
|
|
@@ -33512,7 +34337,7 @@ var PublishedJournalReplay = class {
|
|
|
33512
34337
|
if (!isRecord(resolved) || resolved.id !== id) {
|
|
33513
34338
|
throw new Error("Winning browser snapshot identity is invalid.");
|
|
33514
34339
|
}
|
|
33515
|
-
|
|
34340
|
+
assertSnapshotDefinition(resolved);
|
|
33516
34341
|
}
|
|
33517
34342
|
};
|
|
33518
34343
|
function replayRelevant(value) {
|
|
@@ -33525,9 +34350,9 @@ async function verifyCapturedFile(file, path, captured) {
|
|
|
33525
34350
|
throw new Error("Pi journal replaced or truncated during replay.");
|
|
33526
34351
|
}
|
|
33527
34352
|
}
|
|
33528
|
-
function validateJournalHeader(
|
|
33529
|
-
const header = metadata.find((entry) => entry.value.type === "session");
|
|
33530
|
-
if (header?.value.id !==
|
|
34353
|
+
function validateJournalHeader(index, manager) {
|
|
34354
|
+
const header = index.metadata.find((entry) => entry.value.type === "session");
|
|
34355
|
+
if (header?.value.id !== (index.header?.id ?? manager.getSessionId())) {
|
|
33531
34356
|
throw new Error("Pi session journal identity does not match the active session.");
|
|
33532
34357
|
}
|
|
33533
34358
|
}
|
|
@@ -33544,29 +34369,37 @@ async function openPublishedJournal(path) {
|
|
|
33544
34369
|
async function readBrowserEntries(manager, physical = false) {
|
|
33545
34370
|
const path = manager.getSessionFile();
|
|
33546
34371
|
if (path === void 0 || path.length === 0) {
|
|
34372
|
+
journalIndexes.delete(manager);
|
|
33547
34373
|
return inMemoryEntries(manager, physical);
|
|
33548
34374
|
}
|
|
33549
34375
|
const leaf = physical ? null : manager.getLeafId();
|
|
33550
|
-
|
|
33551
|
-
if (!file) {
|
|
33552
|
-
return inMemoryEntries(manager, physical);
|
|
33553
|
-
}
|
|
34376
|
+
let file;
|
|
33554
34377
|
try {
|
|
34378
|
+
file = await openPublishedJournal(path);
|
|
34379
|
+
if (!file) {
|
|
34380
|
+
journalIndexes.delete(manager);
|
|
34381
|
+
return inMemoryEntries(manager, physical);
|
|
34382
|
+
}
|
|
33555
34383
|
const captured = await file.stat();
|
|
33556
34384
|
if (!captured.isFile()) {
|
|
33557
34385
|
throw new Error("Pi session journal is not a regular file.");
|
|
33558
34386
|
}
|
|
33559
|
-
const
|
|
33560
|
-
|
|
34387
|
+
const index = await readJournalIndex(manager, file, path, captured);
|
|
34388
|
+
const { metadata } = index;
|
|
34389
|
+
validateJournalHeader(index, manager);
|
|
33561
34390
|
const records = metadata.filter((entry) => entry.value.type !== "session");
|
|
33562
34391
|
const selected = physical ? records : branchEntries(records, leaf);
|
|
33563
34392
|
const replay = new PublishedJournalReplay(file, selected, legacyOwner(manager));
|
|
33564
34393
|
await replay.project(selected);
|
|
33565
34394
|
const entries = await replay.resolveWinningDefinitions(physical);
|
|
33566
34395
|
await verifyCapturedFile(file, path, captured);
|
|
34396
|
+
journalIndexes.set(manager, index);
|
|
33567
34397
|
return entries;
|
|
34398
|
+
} catch (error) {
|
|
34399
|
+
journalIndexes.delete(manager);
|
|
34400
|
+
throw error;
|
|
33568
34401
|
} finally {
|
|
33569
|
-
await file
|
|
34402
|
+
await file?.close();
|
|
33570
34403
|
}
|
|
33571
34404
|
}
|
|
33572
34405
|
|
|
@@ -33791,10 +34624,10 @@ init_managed_session_restore();
|
|
|
33791
34624
|
|
|
33792
34625
|
// dist/extensions/agent-browser/lib/orchestration/execution-queue.js
|
|
33793
34626
|
init_argv_grammar();
|
|
33794
|
-
import { AsyncLocalStorage as
|
|
34627
|
+
import { AsyncLocalStorage as AsyncLocalStorage4 } from "node:async_hooks";
|
|
33795
34628
|
var AsyncExecutionQueue = class {
|
|
33796
34629
|
tail = Promise.resolve();
|
|
33797
|
-
active = new
|
|
34630
|
+
active = new AsyncLocalStorage4();
|
|
33798
34631
|
isCurrent() {
|
|
33799
34632
|
return this.active.getStore()?.active === true;
|
|
33800
34633
|
}
|
|
@@ -33897,14 +34730,14 @@ function buildInstalledDocsGuideline(paths) {
|
|
|
33897
34730
|
}
|
|
33898
34731
|
var QUICK_START_GUIDELINES = [
|
|
33899
34732
|
"Choose agent_browser for one native command, native batch --bail with JSON-array stdin for a known fixed sequence, or agent_browser_code for loops, branches, and aggregation. Return to the model when a fresh observation needs judgment. Neither tool is a named recipe registry.",
|
|
33900
|
-
'agent_browser takes args (argv after the binary), optional stdin, outputPath, timeoutMs, and sessionMode. Start with { args: ["open", "<url>"] }, then { args: ["snapshot", "-i"] }; act on current @refs and re-snapshot after navigation or DOM changes. Native commands, providers, plugins, profiles, auth, file access, and caller paths remain available through args.',
|
|
34733
|
+
'agent_browser takes args (argv after the binary), optional stdin, outputPath, timeoutMs, and sessionMode; sessionMode:fresh intentionally launches a separate managed browser. Start with { args: ["open", "<url>"] }, then { args: ["snapshot", "-i"] }; act on current @refs and re-snapshot after navigation or DOM changes. Native commands, providers, plugins, profiles, auth, file access, and caller paths remain available through args; native config and environment pass through. Use requested/configured profiles and verify authentication after restart.',
|
|
33901
34734
|
'Use { args: ["batch", "--bail"], stdin: "[[\\"fill\\",\\"@e1\\",\\"text\\"],[\\"click\\",\\"@e2\\"]]" } for same-snapshot form fields followed by submit. Split if a fill rerenders later fields. Add native condition waits after navigation-prone actions; a click alone does not prove the destination loaded. Avoid blind mutation retries after timeout.',
|
|
33902
34735
|
"agent_browser_code takes { code, session?, namespace?, timeoutMs?, outputPath? }. JavaScript globals are fresh for every call; the selected browser persists and is shared with agent_browser. Use await browser({ args, stdin?, timeoutMs? }), inspect result.success, and emit selected JSON instead of whole envelopes. Use emitImage(result.imageObservations[0]) only when image inspection is needed; image handles belong to the current code call. No imports or host filesystem/network/process APIs are exposed.",
|
|
33903
34736
|
`Example agent_browser_code: { code: 'const result = await browser({args:["get","title"]}); if (!result.success) { emit(result); } else { emit({title:result.data}); }' }. Native batch still avoids extra CLI processes for fixed segments inside code. Explicit session/namespace controls select the browser for this cell without changing the default browser.`,
|
|
33904
34737
|
'Call agent_browser_tools with no fields for inventory, or { enable: ["action", "qa", "electron", "source", "network"] } for advanced native tools. It adds agent_browser_action, agent_browser_qa, agent_browser_electron, agent_browser_source, and agent_browser_network_source without disabling other tools. The browser instructions cover these capabilities; activation reveals their selected tool declarations.',
|
|
33905
34738
|
"Use read <url> for readable web text; get title/url, get text/html/value/count <selector>, or get attr <selector> <name> for targeted state. For eval --stdin, put JavaScript in stdin and return the desired value. outputPath saves result data and must differ from screenshot/download/recording paths. Use --json only when JSON text is needed.",
|
|
33906
|
-
"For artifacts, verify artifactVerification and artifacts before reporting success. A pending recording is not verified output; install ffmpeg before starting and pair start with stop. Native download owns the click and saves Blob/redirect downloads. Close keeps explicitly saved files. Save promptGuard-required paths before close. Screenshot pixels are not browser CSS coordinates: use imageObservations geometry (dimensions, viewport, crop/origin, scroll and DPR) before any visual-coordinate action; full-page and element captures are not current-viewport coordinates, and Pi resizing only maps sent pixels to original image pixels. Lightpanda images are text-rendered, not graphical layout; rendering:text never supports CSS/mouse-coordinate input.",
|
|
33907
|
-
"Follow model-visible nextActions when present, including identity and stdin, instead of guessing commands. Treat native pending confirmations and unknown mutation outcomes as inspection boundaries. For dense snapshots, inspect Omitted high-value controls before reading a full spill."
|
|
34739
|
+
"For artifacts, verify artifactVerification and artifacts before reporting success. A pending recording is not verified output; install ffmpeg before starting and pair start with stop. Native download owns the click and saves Blob/redirect downloads. Close keeps explicitly saved files. Save promptGuard-required paths before close. Screenshot pixels are not browser CSS coordinates: use imageObservations geometry (dimensions, viewport, crop/origin, scroll and DPR) before any visual-coordinate action; full-page and element captures are not current-viewport coordinates, and Pi resizing only maps sent pixels to original image pixels. Lightpanda images are text-rendered, not graphical layout; rendering:text never supports CSS/mouse-coordinate input. Prefer refs; inspect screenshots only when the task needs vision.",
|
|
34740
|
+
"Follow model-visible nextActions when present, including identity and stdin, instead of guessing commands. Treat native pending confirmations and unknown mutation outcomes as inspection boundaries. Native outcome_unknown means a command may have run and was not retried; inspect before any repeat. For dense snapshots, inspect Omitted high-value controls before reading a full spill."
|
|
33908
34741
|
];
|
|
33909
34742
|
var ADVANCED_TOOL_PROMPT_GUIDELINES = {
|
|
33910
34743
|
action: [
|
|
@@ -33946,11 +34779,11 @@ var SHARED_BROWSER_PLAYBOOK_GUIDELINES = [
|
|
|
33946
34779
|
"Do not assume Playwright selector dialects such as text=Close or button:has-text('Close') are supported wrapper syntax unless current upstream agent-browser behavior has been verified.",
|
|
33947
34780
|
"For authenticated or user-specific content explicitly requested by the user, such as feeds, inboxes, account pages, or private dashboards, use a real profile only when the user/config asks for it or profiles have been inspected; do not assume --profile Default exists on every machine. Do not use a real profile for public pages just because they are dashboards. Treat visible page content from real profiles as model-visible transcript data. On macOS, copied Chrome profiles may omit encrypted cookies, so profile selection alone is not proof of authentication; verify the target page and use a user-approved headed login once when needed. Use --auto-connect only if profile-based reuse is unavailable or the task is specifically about attaching to a running debug-enabled browser. If profile/user-data-dir resolution fails, stop retrying opens, run profiles and/or doctor through agent_browser, then report what the user needs to configure.",
|
|
33948
34781
|
"Ordinary bare calls share one native browser within your root Pi parent/subagent group; unrelated roots browse independently. Coordinate multi-call navigation inside your group with existing subagent/intercom tools. Explicit native session defaults still win. Pi quit does not close group browsers; never close an unrelated browser.",
|
|
33949
|
-
`When using launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}), put them on the first command for that session. If you intentionally use an explicit --session, keep using that same explicit session for follow-ups.`,
|
|
34782
|
+
`When using launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}), put them on the first command for that session. If you intentionally use an explicit --session, keep using that same explicit session for follow-ups. If you already used the implicit session and now need launch-scoped flags, retry with top-level sessionMode set to fresh or pass an explicit --session for the new launch; never pass --session-mode inside args. After a successful unnamed fresh launch, later auto calls follow that new session.`,
|
|
33950
34783
|
"Cooperating Pi processes serialize each complete browser operation and code cell by native socket context, namespace, and session, including target/ref helpers and state updates. Different identities remain concurrent; namespace-wide close waits for matching operations. All participating Pi instances must load this release; humans, third-party clients, and older extensions are outside that coordination. It is not a transaction or rollback. For raw batches whose later content depends on navigation, use exact batch --bail or split the calls.",
|
|
33951
34784
|
"After a successful `connect`, `--cdp`, or enabled `--auto-connect` call, verify with get url and keep using the resulting session without repeating the attach flag. The wrapper remembers that attachment across active-branch reload/resume and live-checks the URL before later page reads/interactions because an attached browser can drift externally; caller config, file access, launch arguments, and environment pass through unchanged. A successful close clears the marker. When several named sessions share one Chrome, pass --pin-tab once (AGENT_BROWSER_PIN_TAB) so a closed bound tab fails as tab_gone instead of acting on a neighbor; recover with tab new or tab list. --no-pin-tab turns the sticky pin off. tab list includes each tab's CDP targetId, accepted as a tab ref.",
|
|
33952
|
-
|
|
33953
|
-
"
|
|
34785
|
+
"Chrome is the default. Select separately installed Lightpanda or experimental Obscura explicitly with --engine lightpanda|obscura, environment or native config; use sessionMode:fresh to change a managed engine. Lightpanda text-rendered screenshots never establish graphical layout or mouse coordinates. Obscura has accessibility, iframe and screenshot gaps; read its command-reference limits first. Profiles, headed mode, multi-tab, WebGPU and WebMCP are not parity capabilities; choose Chrome when needed, never assume automatic fallback.",
|
|
34786
|
+
"For CLI HTTPS trust on read/install/upgrade/doctor, use --ca-cert <path> or --use-system-ca; --use-system-ca false disables OS roots and SSL_CERT_FILE is a fallback. These do not disable certificate verification or configure remote CDP trust. Browser CA trust remains Linux-Chromium-only and launch-scoped.",
|
|
33954
34787
|
'For WebGPU pages, use args ["--webgpu", "open", "<url>"] on a fresh local browser launch; use doctor --webgpu (or --headed on Linux/Windows capture paths) to prove rendering before trusting a non-black screenshot. WebGPU cannot be combined with --cdp, --auto-connect, or provider launches unless --webgpu false overrides an enabled config/environment default.',
|
|
33955
34788
|
"For experimental WebMCP page tools, use webmcp list, then webmcp invoke <tool> with --params and optional --frame/--detach/--timeout; use webmcp result or cancel for detached calls. Locally managed Chrome enables WebMCP by default; a positive navigation hint means the page has tools to list. --no-webmcp is launch-scoped and requires a fresh session; invoke/result/cancel can mutate or navigate, so refresh snapshot refs afterward.",
|
|
33956
34789
|
"For --allowed-domains, use a fresh local Chrome context. Upstream rejects CDP/auto-connect, profiles, restore/state replay, direct-page providers, iOS/Safari, and startup/profile Chrome args because they cannot guarantee containment; Chromium also disables RTCPeerConnection while the allowlist is active.",
|
|
@@ -33958,7 +34791,7 @@ var SHARED_BROWSER_PLAYBOOK_GUIDELINES = [
|
|
|
33958
34791
|
"For first-navigation setup, use open without a URL plus network route --resource-type <csv>, cookies set --curl <file>, or --init-script/--enable before navigate/opening the target page.",
|
|
33959
34792
|
"For stateful browser context work, use auth save --password-stdin with the tool stdin field for credentials, auth list/show/delete/remove for local auth-profile maintenance, auth login when you need the browser to fill a saved profile, and state save/load/list/show/rename/clear/clean for upstream saved-state lifecycle. State paths, restore identifiers, wrapper-prefixed sessions, and all upstream list rows remain available; credential values inside cookie/storage/auth payloads are still redacted from presentation.",
|
|
33960
34793
|
"Upstream restore sessions periodically autosave cookies and localStorage while the browser stays open, including page-driven background changes; AGENT_BROWSER_AUTOSAVE_INTERVAL_MS controls the interval (30000 by default; 0 disables periodic saves but keeps save-on-close), while the never value for --restore-save disables automatic saves for that restore session. For wrapper-owned headed launches, the wrapper defaults the interval to 0 because upstream 0.33.2 collects multi-origin storage through visible temporary tabs, then records and reapplies the effective launch-time value to helpers and follow-ups so daemon configuration remains stable. Native close still saves, but direct window close can lose newer state because upstream exempts headed browsers from idle shutdown; set AGENT_BROWSER_AUTOSAVE_INTERVAL_MS before launch when periodic preservation matters, because changing it on a running wrapper-owned headed session requires close plus a fresh launch.",
|
|
33961
|
-
"For batch chains that touch cookies, storage, auth, or other secret-bearing commands, use details.batchSteps for per-step artifacts, categories, spill paths, and full structured errors; top-level details.data on batch is only a compact redacted step matrix (success, argv-redacted command, redacted result or scrubbed error text) built from the same presentation rules as standalone calls.",
|
|
34794
|
+
"For batch chains that touch cookies, storage, auth, or other secret-bearing commands, use details.batchSteps for per-step artifacts, categories, spill paths, and full structured errors; top-level details.data on batch is only a compact redacted step matrix (success, argv-redacted command or native --omit-command index, redacted result or scrubbed error text) built from the same presentation rules as standalone calls. Indexed receipts preserve original input positions, including skipped empty rows, without echoing commands.",
|
|
33962
34795
|
"For non-core families, pass current upstream commands through the native tool directly: network requests, network route <url>, network har start/stop [path], diff snapshot, diff screenshot --baseline <file>, diff url <u1> <u2>, trace start, trace stop [path], profiler start, profiler stop [path], record start <path>, record stop, console/errors [--clear], highlight <selector>, inspect, clipboard read, clipboard write <text>, clipboard copy/paste, stream enable/disable/status, dashboard start/stop, device list for iOS simulator inventory, and chat <message>. For compact network requests output, prefer details.nextActions for request detail, route-mock diagnostics, actionable failed-request agent_browser_network_source, filtering, clearing the aggregate buffer before repro, or HAR capture follow-ups instead of guessing request-id syntax. Artifact-producing commands report details.artifacts and verification state; long-running starts such as stream, dashboard, trace/profiler, and record should be paired with the matching stop/disable command when the task is done; stream enable already-enabled outcomes are treated as idempotent success with status/disable follow-ups.",
|
|
33963
34796
|
'For Electron desktop apps, enable agent_browser_electron through agent_browser_tools for wrapper-owned discovery, isolated launch, status, compact probe, and cleanup: list first, treat likely-sensitive annotations as hints rather than enforcement, launch with the default snapshot handoff unless handoff: "tabs" is the safer diagnostic starting point, use agent_browser_electron probe or snapshot -i/agent_browser_qa attached:true for current-session state, and always cleanup the returned launchId when done. agent_browser_electron launch uses an isolated temporary profile; it does not reuse the app\'s normal signed-in profile or attach to an already-running authenticated app. For signed-in local app state, host-launch the normal app with --remote-debugging-port when appropriate, then use raw args connect <port|url>; after connect, run get url to verify the active target before page-content reads, inspect tab list, select the stable tab id such as tab t2, verify it again with get url, then run a condition wait or snapshot -i before using refs. close commands (`close`, `quit`, or `exit`) only close the browser/CDP session; leave manually launched app shutdown, profile cleanup, and explicit artifacts to the host owner.',
|
|
33964
34797
|
"For provider or specialized app workflows, load version-matched upstream guidance with skills get agentcore|electron|slack|dogfood|vercel-sandbox|derive-client through the native tool; add --full when you need references/templates, and use skills get --all only for broad skill audits. Use derive-client when recording HAR traffic to generate a standalone API client; prefer network har start (text bodies by default) or network har start --content all|none before multi-step capture. For accessibility audits use a11y or a11y --tags wcag2a,wcag2aa (CDP browsers only). Hosted sandbox workflows should use upstream @agent-browser/sandbox helpers outside this wrapper. Provider launches such as -p ios, --provider browserbase/kernel/browseruse/browserless/agentcore, and iOS --device are upstream-owned setup paths; use sessionMode fresh when switching providers and expect external credentials or local Appium/Xcode setup to be required.",
|
|
@@ -33976,6 +34809,7 @@ var SHARED_BROWSER_PLAYBOOK_GUIDELINES = [
|
|
|
33976
34809
|
"For evidence-only screenshots, QA captures, or other audit artifacts, save to an explicit path and branch on details.artifactVerification plus details.artifacts before reporting PASS/FAIL; do not require vision review of inline image attachments unless the user asked for visual inspection.",
|
|
33977
34810
|
"Respect explicit user stop boundaries yourself. When the surrounding authenticated employee or automation context is explicitly unattended/auto-approved, ordinary non-destructive form submissions within the requested flow may proceed without separate confirmation. Still require explicit authorization for purchases, production-control actions, destructive or irreversible actions, and account, security, or privacy changes. The wrapper does not infer broad business intent from prompt text; details.promptGuard is reserved for concrete artifact-before-close checks.",
|
|
33978
34811
|
"Recording needs ffmpeg on PATH before start. Current upstream checks it at startup; older natives may defer failure. A pending recording is not verified output.",
|
|
34812
|
+
"Native 0.41 mcp call and stdin-driven MCP can finish normally, but this wrapper currently rejects all non-help mcp invocations. Session/namespace coordination and credential/image presentation are not integrated; use ordinary agent_browser commands.",
|
|
33979
34813
|
"Do not call --help or other exploratory inspection commands unless the user explicitly asks for them or debugging the browser integration is necessary."
|
|
33980
34814
|
];
|
|
33981
34815
|
var TOOL_PROMPT_GUIDELINES_SUFFIX = [
|
|
@@ -34020,7 +34854,7 @@ function buildToolPromptGuidelines(options) {
|
|
|
34020
34854
|
return [
|
|
34021
34855
|
...options.includeWebSearch ? ["Prefer agent_browser_web_search for facts; agent_browser for pages."] : TOOL_PROMPT_GUIDELINES_PREFIX,
|
|
34022
34856
|
...options.docs ? [buildInstalledDocsGuideline(options.docs)] : [],
|
|
34023
|
-
...RUNTIME_PROMPT_GUIDELINES,
|
|
34857
|
+
...options.compact ? RUNTIME_PROMPT_GUIDELINES : [],
|
|
34024
34858
|
...browserExecutablePathGuideline !== void 0 ? [browserExecutablePathGuideline] : [],
|
|
34025
34859
|
...browserDefaultProfileGuideline !== void 0 ? [browserDefaultProfileGuideline] : [],
|
|
34026
34860
|
TOOL_PROMPT_GUIDELINES_SUFFIX[0]
|
|
@@ -36376,11 +37210,13 @@ function sleepWithAbort(ms, signal) {
|
|
|
36376
37210
|
});
|
|
36377
37211
|
}
|
|
36378
37212
|
var WebSearchRequestGate = class {
|
|
37213
|
+
// A performance.now() timestamp (0 before the first request), so a system clock step neither
|
|
37214
|
+
// skips nor extends the spacing between requests.
|
|
36379
37215
|
lastRequestStartedAt = 0;
|
|
36380
37216
|
tail = Promise.resolve();
|
|
36381
37217
|
run(signal, task) {
|
|
36382
37218
|
const runTask = async () => {
|
|
36383
|
-
const elapsedMs = this.lastRequestStartedAt === 0 ? WEB_SEARCH_MIN_REQUEST_INTERVAL_MS :
|
|
37219
|
+
const elapsedMs = this.lastRequestStartedAt === 0 ? WEB_SEARCH_MIN_REQUEST_INTERVAL_MS : performance.now() - this.lastRequestStartedAt;
|
|
36384
37220
|
const waitMs = Math.max(0, WEB_SEARCH_MIN_REQUEST_INTERVAL_MS - elapsedMs);
|
|
36385
37221
|
if (waitMs > 0) {
|
|
36386
37222
|
await sleepWithAbort(waitMs, signal);
|
|
@@ -36388,7 +37224,7 @@ var WebSearchRequestGate = class {
|
|
|
36388
37224
|
if (signal?.aborted === true) {
|
|
36389
37225
|
signal.throwIfAborted();
|
|
36390
37226
|
}
|
|
36391
|
-
this.lastRequestStartedAt =
|
|
37227
|
+
this.lastRequestStartedAt = performance.now();
|
|
36392
37228
|
return task();
|
|
36393
37229
|
};
|
|
36394
37230
|
const result = this.tail.then(runTask, runTask);
|
|
@@ -36761,7 +37597,7 @@ function createAgentBrowserWebSearchTool(configState, options = {}) {
|
|
|
36761
37597
|
|
|
36762
37598
|
// dist/extensions/agent-browser/lib/bash-guard.js
|
|
36763
37599
|
init_parsing();
|
|
36764
|
-
import { readFile as
|
|
37600
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
36765
37601
|
import { join as join14 } from "node:path";
|
|
36766
37602
|
var DIRECT_AGENT_BROWSER_BASH_BYPASS_ENV = "PI_AGENT_BROWSER_ALLOW_DIRECT_BASH";
|
|
36767
37603
|
var DIRECT_AGENT_BROWSER_EXECUTABLE_PATTERN = /^(?:[.~]|\.\.?|\/)?(?:[^\s;&|]+\/)?agent-browser$/;
|
|
@@ -36934,7 +37770,7 @@ function isTruthyEnvValue(value) {
|
|
|
36934
37770
|
}
|
|
36935
37771
|
async function isPackageDevelopmentCwd(cwd) {
|
|
36936
37772
|
try {
|
|
36937
|
-
const packageJson = JSON.parse(await
|
|
37773
|
+
const packageJson = JSON.parse(await readFile5(join14(cwd, "package.json"), "utf8"));
|
|
36938
37774
|
return isRecord(packageJson) && packageJson.name === PACKAGE_NAME;
|
|
36939
37775
|
} catch {
|
|
36940
37776
|
return false;
|
|
@@ -36945,6 +37781,16 @@ async function isDirectAgentBrowserBashAllowed(cwd) {
|
|
|
36945
37781
|
}
|
|
36946
37782
|
|
|
36947
37783
|
// dist/extensions/agent-browser/lib/orchestration/extension-prompt.js
|
|
37784
|
+
var COMPACT_FALLBACK_ENV = "AGENT_BROWSER_COMPACT_FALLBACK";
|
|
37785
|
+
var PLAYBOOK_MODE_ENV = "AGENT_BROWSER_PLAYBOOK";
|
|
37786
|
+
function isCompactFallbackEnabled() {
|
|
37787
|
+
const compactEnv = process.env[COMPACT_FALLBACK_ENV]?.trim().toLowerCase();
|
|
37788
|
+
if (compactEnv === "1" || compactEnv === "true" || compactEnv === "yes") {
|
|
37789
|
+
return true;
|
|
37790
|
+
}
|
|
37791
|
+
const playbookEnv = process.env[PLAYBOOK_MODE_ENV]?.trim().toLowerCase();
|
|
37792
|
+
return playbookEnv === "compact" || playbookEnv === "minimal" || playbookEnv === "0" || playbookEnv === "false";
|
|
37793
|
+
}
|
|
36948
37794
|
function isBashToolCallEvent(event) {
|
|
36949
37795
|
return isRecord(event) && event.toolName === "bash" && isRecord(event.input) && typeof event.input.command === "string";
|
|
36950
37796
|
}
|
|
@@ -36981,6 +37827,7 @@ function shouldIncludeProjectConfig(ctx, argv = process.argv) {
|
|
|
36981
37827
|
}
|
|
36982
37828
|
var BrowserPrompt = class {
|
|
36983
37829
|
pi;
|
|
37830
|
+
docsPaths;
|
|
36984
37831
|
state;
|
|
36985
37832
|
webSearchToolRegistered = false;
|
|
36986
37833
|
constructor(pi) {
|
|
@@ -37018,7 +37865,7 @@ var BrowserPrompt = class {
|
|
|
37018
37865
|
});
|
|
37019
37866
|
this.webSearchToolRegistered = true;
|
|
37020
37867
|
}
|
|
37021
|
-
instructions(ctx) {
|
|
37868
|
+
instructions(ctx, options) {
|
|
37022
37869
|
const config = loadAgentBrowserConfigSync({
|
|
37023
37870
|
cwd: ctx.cwd,
|
|
37024
37871
|
includeProjectConfig: shouldIncludeProjectConfig(ctx)
|
|
@@ -37031,18 +37878,22 @@ var BrowserPrompt = class {
|
|
|
37031
37878
|
|
|
37032
37879
|
Project agent_browser config guidance:
|
|
37033
37880
|
${guidance.map((line) => `- ${line}`).join("\n")}` : "";
|
|
37881
|
+
const compact = !(options?.forceFull ?? false) && isCompactFallbackEnabled();
|
|
37034
37882
|
const guidelines = [
|
|
37035
37883
|
...buildToolPromptGuidelines({
|
|
37884
|
+
compact,
|
|
37036
37885
|
browserDefaultProfile: config.trustedBrowserDefaultProfile,
|
|
37037
37886
|
browserExecutablePath: config.trustedBrowserExecutablePath,
|
|
37038
37887
|
includeWebSearch: this.webSearchToolRegistered,
|
|
37039
|
-
docs: getInstalledDocsPaths()
|
|
37888
|
+
docs: this.docsPaths ??= getInstalledDocsPaths()
|
|
37040
37889
|
}),
|
|
37041
|
-
...
|
|
37042
|
-
|
|
37043
|
-
|
|
37044
|
-
|
|
37045
|
-
|
|
37890
|
+
...compact ? [] : [
|
|
37891
|
+
...QUICK_START_GUIDELINES,
|
|
37892
|
+
...SHARED_BROWSER_PLAYBOOK_GUIDELINES,
|
|
37893
|
+
...WRAPPER_TAB_RECOVERY_BEHAVIOR,
|
|
37894
|
+
...Object.values(ADVANCED_TOOL_PROMPT_GUIDELINES).flat(),
|
|
37895
|
+
...this.webSearchToolRegistered ? WEB_SEARCH_TOOL_PROMPT_GUIDELINES : []
|
|
37896
|
+
]
|
|
37046
37897
|
];
|
|
37047
37898
|
return `${PROJECT_RULE_PROMPT}
|
|
37048
37899
|
|
|
@@ -37064,7 +37915,7 @@ ${[...new Set(guidelines)].map((line) => `- ${line}`).join("\n")}${configPrompt}
|
|
|
37064
37915
|
"agent_browser_web_search",
|
|
37065
37916
|
...Object.values(AGENT_BROWSER_TOOL_INVENTORY).map(({ name }) => name)
|
|
37066
37917
|
],
|
|
37067
|
-
instructions: (ctx) => this.instructions(ctx)
|
|
37918
|
+
instructions: (ctx) => this.instructions(ctx, { forceFull: true })
|
|
37068
37919
|
}
|
|
37069
37920
|
]);
|
|
37070
37921
|
setManaged(() => {
|
|
@@ -37237,10 +38088,9 @@ function syncOwnedManagedSessionsFromResult(sessions, result, cwd) {
|
|
|
37237
38088
|
retireOutcomeOwner(sessions, outcome, details, current);
|
|
37238
38089
|
}
|
|
37239
38090
|
async function closeOwnedManagedSessionsExcept(sessions, pages, settings, options) {
|
|
37240
|
-
const keepKey = getSessionContextKey(options.keepSessionName, options.keepNamespace);
|
|
37241
38091
|
const owners = Array.from(sessions);
|
|
37242
38092
|
for (const [key, owner] of owners) {
|
|
37243
|
-
if (key
|
|
38093
|
+
if (options.keepKeys.has(key)) {
|
|
37244
38094
|
continue;
|
|
37245
38095
|
}
|
|
37246
38096
|
const error = await closeManagedSession({
|
|
@@ -38421,8 +39271,8 @@ init_managed_session_daemon_policy();
|
|
|
38421
39271
|
|
|
38422
39272
|
// dist/extensions/agent-browser/lib/input-modes/script.js
|
|
38423
39273
|
init_types();
|
|
38424
|
-
import { existsSync as existsSync4 } from "node:fs";
|
|
38425
|
-
import { dirname as
|
|
39274
|
+
import { existsSync as existsSync4, realpathSync as realpathSync5 } from "node:fs";
|
|
39275
|
+
import { dirname as dirname14, join as join28 } from "node:path";
|
|
38426
39276
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
38427
39277
|
import which2 from "which";
|
|
38428
39278
|
|
|
@@ -38955,19 +39805,19 @@ function resolveScriptChildNodePath(options) {
|
|
|
38955
39805
|
return nodePath;
|
|
38956
39806
|
}
|
|
38957
39807
|
function resolveScriptWorkerPath() {
|
|
38958
|
-
let currentDir =
|
|
38959
|
-
while (!existsSync4(
|
|
38960
|
-
const parentDir =
|
|
39808
|
+
let currentDir = dirname14(fileURLToPath2(import.meta.url));
|
|
39809
|
+
while (!existsSync4(join28(currentDir, "package.json"))) {
|
|
39810
|
+
const parentDir = dirname14(currentDir);
|
|
38961
39811
|
if (parentDir === currentDir) {
|
|
38962
39812
|
throw new Error("Unable to resolve the pi-agent-browser-native package root.");
|
|
38963
39813
|
}
|
|
38964
39814
|
currentDir = parentDir;
|
|
38965
39815
|
}
|
|
38966
|
-
const workerPath =
|
|
39816
|
+
const workerPath = join28(currentDir, "dist", "extensions", "agent-browser", "script-worker.js");
|
|
38967
39817
|
if (!existsSync4(workerPath)) {
|
|
38968
39818
|
throw new Error("Compiled script worker is missing; run npm run build or reinstall pi-agent-browser-native.");
|
|
38969
39819
|
}
|
|
38970
|
-
return workerPath;
|
|
39820
|
+
return realpathSync5(workerPath);
|
|
38971
39821
|
}
|
|
38972
39822
|
function createAgentBrowserScriptCloseArgs(sessionName) {
|
|
38973
39823
|
return ["--namespace", AGENT_BROWSER_SCRIPT_NAMESPACE, "--session", sessionName, "close"];
|
|
@@ -39821,6 +40671,21 @@ function restoreAttachedSessionKeysFromBranch(branch) {
|
|
|
39821
40671
|
}
|
|
39822
40672
|
|
|
39823
40673
|
// dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js
|
|
40674
|
+
function isActiveOnBranch(events, key) {
|
|
40675
|
+
const active = events.managedSessionActiveRanks.get(key);
|
|
40676
|
+
const closed = events.managedSessionCloseRanks.get(key);
|
|
40677
|
+
return active !== void 0 && (closed === void 0 || closed < active);
|
|
40678
|
+
}
|
|
40679
|
+
function* restorableBranchManagedIdentities(events, baseName) {
|
|
40680
|
+
for (const [key, identity] of events.managedSessionActiveIdentities) {
|
|
40681
|
+
if (isActiveOnBranch(events, key) && isRestorableManagedSessionName(identity.sessionName, baseName)) {
|
|
40682
|
+
yield [key, identity];
|
|
40683
|
+
}
|
|
40684
|
+
}
|
|
40685
|
+
}
|
|
40686
|
+
function getOwnerKey(sessionName, namespace) {
|
|
40687
|
+
return getSessionContextKey(sessionName, typeof namespace === "string" ? namespace : void 0) ?? sessionName;
|
|
40688
|
+
}
|
|
39824
40689
|
async function readBranchForRestore(runtime, ctx, resetRuntimeOwnership) {
|
|
39825
40690
|
runtime.branch.beginRestore(ctx.sessionManager.getSessionId());
|
|
39826
40691
|
runtime.prompt.restore(ctx);
|
|
@@ -39924,7 +40789,7 @@ var BrowserBranchRestoration = class {
|
|
|
39924
40789
|
}
|
|
39925
40790
|
}
|
|
39926
40791
|
restoreManagedOwners() {
|
|
39927
|
-
for (const [sessionKey, identity] of this.branchResourceEvents.
|
|
40792
|
+
for (const [sessionKey, identity] of restorableBranchManagedIdentities(this.branchResourceEvents, this.runtime.managed.baseName)) {
|
|
39928
40793
|
this.restoreBranchManagedOwner(sessionKey, identity);
|
|
39929
40794
|
}
|
|
39930
40795
|
if (this.restoredState.active) {
|
|
@@ -39939,14 +40804,9 @@ var BrowserBranchRestoration = class {
|
|
|
39939
40804
|
}
|
|
39940
40805
|
}
|
|
39941
40806
|
sessionActiveOnBranch(key) {
|
|
39942
|
-
|
|
39943
|
-
const closed = this.branchResourceEvents.managedSessionCloseRanks.get(key);
|
|
39944
|
-
return active !== void 0 && (closed === void 0 || closed < active);
|
|
40807
|
+
return isActiveOnBranch(this.branchResourceEvents, key);
|
|
39945
40808
|
}
|
|
39946
40809
|
restoreBranchManagedOwner(key, identity) {
|
|
39947
|
-
if (!this.sessionActiveOnBranch(key) || !isRestorableManagedSessionName(identity.sessionName, this.runtime.managed.baseName)) {
|
|
39948
|
-
return;
|
|
39949
|
-
}
|
|
39950
40810
|
const launch = this.branchResourceEvents.managedSessionLaunchState.get(key);
|
|
39951
40811
|
trackOwnedManagedSession(this.runtime.managed.owned, identity.sessionName, launch?.cwd ?? this.ctx.cwd, {
|
|
39952
40812
|
branchOwned: true,
|
|
@@ -40047,6 +40907,24 @@ async function restoreBranchBackedState(runtime, ctx, options) {
|
|
|
40047
40907
|
const input = await readBranchForRestore(runtime, ctx, options.resetRuntimeOwnership);
|
|
40048
40908
|
return new BrowserBranchRestoration(runtime, ctx, input).run();
|
|
40049
40909
|
}
|
|
40910
|
+
async function readTransferableManagedSessionKeys(runtime, ctx) {
|
|
40911
|
+
const branch = await readBrowserEntries(ctx.sessionManager);
|
|
40912
|
+
const { baseName } = runtime.managed;
|
|
40913
|
+
const keys = /* @__PURE__ */ new Set();
|
|
40914
|
+
for (const [key] of restorableBranchManagedIdentities(collectBranchManagedResourceEvents(branch), baseName)) {
|
|
40915
|
+
keys.add(key);
|
|
40916
|
+
}
|
|
40917
|
+
const current = restoreManagedSessionStateFromBranch([...branch], baseName);
|
|
40918
|
+
if (current.active) {
|
|
40919
|
+
keys.add(getOwnerKey(current.sessionName, current.namespace));
|
|
40920
|
+
}
|
|
40921
|
+
for (const begin of collectPendingOwnedBrowserIntents(branch, runtime.branch.ownerSessionId)) {
|
|
40922
|
+
if (typeof begin.state.sessionName === "string") {
|
|
40923
|
+
keys.add(getOwnerKey(begin.state.sessionName, begin.state.namespace));
|
|
40924
|
+
}
|
|
40925
|
+
}
|
|
40926
|
+
return keys;
|
|
40927
|
+
}
|
|
40050
40928
|
|
|
40051
40929
|
// dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js
|
|
40052
40930
|
var BrowserLifecycle = class {
|
|
@@ -40076,8 +40954,22 @@ var BrowserLifecycle = class {
|
|
|
40076
40954
|
await this.runtime.code.settle();
|
|
40077
40955
|
await this.runtime.managedSessionExecutionQueue.run(() => this.runtime.artifacts.queue.run(() => this.restore(ctx, false)));
|
|
40078
40956
|
}
|
|
40079
|
-
async
|
|
40957
|
+
async retainedManagedSessionKeys(ctx, scope) {
|
|
40958
|
+
const { managed } = this.runtime;
|
|
40959
|
+
if (scope === "quit") {
|
|
40960
|
+
return /* @__PURE__ */ new Set();
|
|
40961
|
+
}
|
|
40962
|
+
if (scope === "restart" && ctx) {
|
|
40963
|
+
try {
|
|
40964
|
+
return await readTransferableManagedSessionKeys(this.runtime, ctx);
|
|
40965
|
+
} catch {
|
|
40966
|
+
}
|
|
40967
|
+
}
|
|
40968
|
+
return managed.active ? /* @__PURE__ */ new Set([getSessionContextKey(managed.name, managed.namespace) ?? managed.name]) : /* @__PURE__ */ new Set();
|
|
40969
|
+
}
|
|
40970
|
+
async cleanup(ctx, scope) {
|
|
40080
40971
|
const { runtime } = this;
|
|
40972
|
+
const quitting = scope === "quit";
|
|
40081
40973
|
const active = getActiveElectronRecords(runtime.electron.records);
|
|
40082
40974
|
const preserved = quitting ? active.filter((record) => !runtime.electron.ownedRecords.has(record.launchId)).map((record) => record.userDataDir) : active.map((record) => record.userDataDir);
|
|
40083
40975
|
const records = quitting ? runtime.electron.ownedRecords : getOffBranchOwnedElectronLaunchRecords(runtime.electron.ownedRecords, runtime.electron.records);
|
|
@@ -40102,8 +40994,7 @@ var BrowserLifecycle = class {
|
|
|
40102
40994
|
restore: runtime.managed.restore,
|
|
40103
40995
|
timeoutMs: runtime.implicitSessionCloseTimeoutMs
|
|
40104
40996
|
}, {
|
|
40105
|
-
|
|
40106
|
-
keepNamespace: !quitting && runtime.managed.active ? runtime.managed.namespace : void 0,
|
|
40997
|
+
keepKeys: await this.retainedManagedSessionKeys(ctx, scope),
|
|
40107
40998
|
onClosed: (owner) => runtime.recordings.retire(owner.sessionName, owner.namespace)
|
|
40108
40999
|
});
|
|
40109
41000
|
runtime.recordings.flush();
|
|
@@ -40118,22 +41009,25 @@ var BrowserLifecycle = class {
|
|
|
40118
41009
|
runtime.recordings.resetIfClean();
|
|
40119
41010
|
runtime.electron.reset();
|
|
40120
41011
|
}
|
|
40121
|
-
async shutdown(ctx,
|
|
41012
|
+
async shutdown(ctx, scope) {
|
|
40122
41013
|
await this.runtime.code.settle();
|
|
40123
41014
|
this.runtime.branch.invalidate();
|
|
40124
|
-
const preservePaths = await this.runtime.managedSessionExecutionQueue.run(() => this.runtime.artifacts.queue.run(() => this.cleanup(ctx,
|
|
41015
|
+
const preservePaths = await this.runtime.managedSessionExecutionQueue.run(() => this.runtime.artifacts.queue.run(() => this.cleanup(ctx, scope)));
|
|
40125
41016
|
this.reset();
|
|
40126
41017
|
await cleanupSecureTempArtifacts({ preservePaths });
|
|
40127
41018
|
}
|
|
40128
41019
|
};
|
|
40129
|
-
function
|
|
40130
|
-
|
|
41020
|
+
function getShutdownScope(event) {
|
|
41021
|
+
if (event?.reason !== "quit") {
|
|
41022
|
+
return "replace";
|
|
41023
|
+
}
|
|
41024
|
+
return event.disposition === "handoff" || event.disposition === "provisional" ? "restart" : "quit";
|
|
40131
41025
|
}
|
|
40132
41026
|
function registerBrowserLifecycle(runtime) {
|
|
40133
41027
|
const lifecycle = new BrowserLifecycle(runtime);
|
|
40134
41028
|
runtime.pi.on("session_start", (_event, ctx) => lifecycle.start(ctx));
|
|
40135
41029
|
runtime.pi.on("session_tree", (_event, ctx) => lifecycle.tree(ctx));
|
|
40136
|
-
runtime.pi.on("session_shutdown", (event, ctx) => lifecycle.shutdown(ctx,
|
|
41030
|
+
runtime.pi.on("session_shutdown", (event, ctx) => lifecycle.shutdown(ctx, getShutdownScope(event)));
|
|
40137
41031
|
}
|
|
40138
41032
|
|
|
40139
41033
|
// dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js
|
|
@@ -40264,14 +41158,14 @@ init_process_environment();
|
|
|
40264
41158
|
init_runtime();
|
|
40265
41159
|
import { createHash as createHash6 } from "node:crypto";
|
|
40266
41160
|
import { homedir as homedir4 } from "node:os";
|
|
40267
|
-
import { join as
|
|
41161
|
+
import { join as join29, resolve as resolve13 } from "node:path";
|
|
40268
41162
|
|
|
40269
41163
|
// dist/extensions/agent-browser/lib/orchestration/native-config.js
|
|
40270
41164
|
init_parsing();
|
|
40271
41165
|
init_argv_grammar();
|
|
40272
41166
|
init_process();
|
|
40273
41167
|
init_envelope();
|
|
40274
|
-
import { readFile as
|
|
41168
|
+
import { readFile as readFile10, rm as rm12 } from "node:fs/promises";
|
|
40275
41169
|
var VALUE_DEFAULTS = [
|
|
40276
41170
|
"executablePath",
|
|
40277
41171
|
"profile",
|
|
@@ -40326,7 +41220,7 @@ function requestsLaunch(config, options) {
|
|
|
40326
41220
|
}
|
|
40327
41221
|
async function readConfigFile(path) {
|
|
40328
41222
|
try {
|
|
40329
|
-
const config = JSON.parse(await
|
|
41223
|
+
const config = JSON.parse(await readFile10(path, "utf8"));
|
|
40330
41224
|
if (!isRecord(config)) {
|
|
40331
41225
|
return void 0;
|
|
40332
41226
|
}
|
|
@@ -40819,7 +41713,16 @@ function cliValue2(args, flag) {
|
|
|
40819
41713
|
function requestsConnection(tokens, stdin) {
|
|
40820
41714
|
return tokens[0] === "connect" || getUpstreamEffectiveBatchSteps(tokens, stdin).some((step) => requestsConnection(step));
|
|
40821
41715
|
}
|
|
40822
|
-
function
|
|
41716
|
+
function rootPiSessionId(sessionId) {
|
|
41717
|
+
const root = process.env.PI_INTERCOM_ROOT_SESSION_ID;
|
|
41718
|
+
if (root !== void 0 && root !== "" && root === root.trim() && root === process.env.PI_INTERCOM_PARENT_SESSION_ID) {
|
|
41719
|
+
return root;
|
|
41720
|
+
}
|
|
41721
|
+
const legacyRoot = process.env.PI_SUBAGENT_ROOT_SESSION_ID;
|
|
41722
|
+
return process.env.PI_SUBAGENT_CHILD === "1" && legacyRoot !== void 0 && legacyRoot !== "" ? legacyRoot : sessionId;
|
|
41723
|
+
}
|
|
41724
|
+
function rootBrowserSessionName(sessionId) {
|
|
41725
|
+
const rootSessionId = rootPiSessionId(sessionId);
|
|
40823
41726
|
return `pi-root-${createHash6("sha256").update(rootSessionId).digest("hex").slice(0, 24)}`;
|
|
40824
41727
|
}
|
|
40825
41728
|
function nativeBooleanOverrides(args) {
|
|
@@ -40850,10 +41753,10 @@ var NativeSessionCall = class {
|
|
|
40850
41753
|
const configArg = scanUpstreamGlobalFlagOccurrences([...input.toolArgs], "--config").at(0);
|
|
40851
41754
|
this.configPath = configArg?.value ?? this.env.AGENT_BROWSER_CONFIG;
|
|
40852
41755
|
this.configPaths = this.configPath !== void 0 ? [resolve13(context2.cwd, this.configPath)] : [
|
|
40853
|
-
|
|
40854
|
-
|
|
41756
|
+
join29(homedir4(), ".agent-browser", "config.json"),
|
|
41757
|
+
join29(context2.cwd, "agent-browser.json")
|
|
40855
41758
|
];
|
|
40856
|
-
this.rootName = context2.root === void 0 ? void 0 : rootBrowserSessionName(context2.root.
|
|
41759
|
+
this.rootName = context2.root === void 0 ? void 0 : rootBrowserSessionName(context2.root.sessionId);
|
|
40857
41760
|
this.browserCommand = input.kind !== "electron" && needsManagedSession(parseArgvDescriptor([...input.toolArgs]), input.toolStdin);
|
|
40858
41761
|
const session = extractExplicitSessionName([...input.toolArgs]);
|
|
40859
41762
|
this.rootFallback = context2.root !== void 0 && this.env.AGENT_BROWSER_SESSION === void 0 && (session === void 0 || session === this.rootName) && this.browserCommand;
|
|
@@ -40922,10 +41825,10 @@ var NativeSessionCall = class {
|
|
|
40922
41825
|
};
|
|
40923
41826
|
}
|
|
40924
41827
|
booleanEnvironment(args) {
|
|
40925
|
-
const
|
|
41828
|
+
const debug2 = getBooleanFlagValue([...args], "--debug");
|
|
40926
41829
|
const noAutoDialog = getBooleanFlagValue([...args], "--no-auto-dialog");
|
|
40927
41830
|
return {
|
|
40928
|
-
...
|
|
41831
|
+
...debug2 !== void 0 ? { AGENT_BROWSER_DEBUG: debug2 ? "1" : void 0 } : {},
|
|
40929
41832
|
...noAutoDialog !== void 0 ? { AGENT_BROWSER_NO_AUTO_DIALOG: noAutoDialog ? "1" : "0" } : {}
|
|
40930
41833
|
};
|
|
40931
41834
|
}
|
|
@@ -40988,18 +41891,18 @@ async function withNativeSessionDefaults(input, context2, run) {
|
|
|
40988
41891
|
// dist/extensions/agent-browser/lib/execution-cwd.js
|
|
40989
41892
|
init_parsing();
|
|
40990
41893
|
import { readFileSync as readFileSync6, statSync as statSync4 } from "node:fs";
|
|
40991
|
-
import { dirname as
|
|
41894
|
+
import { dirname as dirname15, isAbsolute as isAbsolute11, join as join30 } from "node:path";
|
|
40992
41895
|
function isDirectoryOwner(source) {
|
|
40993
41896
|
if (/^(?:npm:pi-change-working-dir|git:github\.com\/fitchmultz\/pi-change-working-dir(?:\.git)?)(?:@.+)?$/.test(source.source)) {
|
|
40994
41897
|
return true;
|
|
40995
41898
|
}
|
|
40996
|
-
const directories = [source.baseDir, isAbsolute11(source.path) ?
|
|
41899
|
+
const directories = [source.baseDir, isAbsolute11(source.path) ? dirname15(source.path) : void 0];
|
|
40997
41900
|
return directories.some((directory) => {
|
|
40998
41901
|
if (directory === void 0 || directory.length === 0 || !isAbsolute11(directory)) {
|
|
40999
41902
|
return false;
|
|
41000
41903
|
}
|
|
41001
41904
|
try {
|
|
41002
|
-
const manifest = JSON.parse(readFileSync6(
|
|
41905
|
+
const manifest = JSON.parse(readFileSync6(join30(directory, "package.json"), "utf8"));
|
|
41003
41906
|
return isRecord(manifest) && manifest.name === "pi-change-working-dir";
|
|
41004
41907
|
} catch {
|
|
41005
41908
|
return false;
|
|
@@ -41053,8 +41956,8 @@ init_argv_grammar();
|
|
|
41053
41956
|
init_artifact_manifest();
|
|
41054
41957
|
init_runtime();
|
|
41055
41958
|
init_text();
|
|
41056
|
-
import { mkdir as mkdir5, readFile as
|
|
41057
|
-
import { dirname as
|
|
41959
|
+
import { mkdir as mkdir5, readFile as readFile11, realpath as realpath3, stat as stat14, writeFile as writeFile3 } from "node:fs/promises";
|
|
41960
|
+
import { dirname as dirname16, extname as extname7, isAbsolute as isAbsolute12, resolve as resolve14 } from "node:path";
|
|
41058
41961
|
function normalizeRequestedOutputPath(path) {
|
|
41059
41962
|
return path.startsWith("@") ? path.slice(1) : path;
|
|
41060
41963
|
}
|
|
@@ -41090,7 +41993,7 @@ async function readCompactedSpill(path, manifest) {
|
|
|
41090
41993
|
if (path === void 0 || path.length === 0 || live !== true) {
|
|
41091
41994
|
throw new Error("Full compacted output is unavailable from the wrapper-managed spill; outputPath was not written.");
|
|
41092
41995
|
}
|
|
41093
|
-
const text3 = await
|
|
41996
|
+
const text3 = await readFile11(path, "utf8");
|
|
41094
41997
|
if (extname7(path) !== ".json") {
|
|
41095
41998
|
return text3;
|
|
41096
41999
|
}
|
|
@@ -41247,7 +42150,7 @@ async function saveOutput(result, destination, preserveText) {
|
|
|
41247
42150
|
const payload = await getOutputPayload(result);
|
|
41248
42151
|
const serialized = typeof payload.value === "string" ? payload.value : `${JSON.stringify(payload.value, null, 2)}
|
|
41249
42152
|
`;
|
|
41250
|
-
await mkdir5(
|
|
42153
|
+
await mkdir5(dirname16(destination.absolutePath), { recursive: true });
|
|
41251
42154
|
await writeFile3(destination.absolutePath, serialized, "utf8");
|
|
41252
42155
|
const bytes = Buffer.byteLength(serialized, "utf8");
|
|
41253
42156
|
const outputFile = {
|
|
@@ -41298,7 +42201,7 @@ init_batch_stdin();
|
|
|
41298
42201
|
function parseRawArtifactSteps(commands) {
|
|
41299
42202
|
const steps = [];
|
|
41300
42203
|
for (const command of commands) {
|
|
41301
|
-
if (command
|
|
42204
|
+
if (isNativeBatchOption(command)) {
|
|
41302
42205
|
continue;
|
|
41303
42206
|
}
|
|
41304
42207
|
const parsed = parseBatchCommandArgument(command);
|
|
@@ -41559,7 +42462,7 @@ var OperationPathBinding = class {
|
|
|
41559
42462
|
}
|
|
41560
42463
|
bindRawBatchRows() {
|
|
41561
42464
|
for (let index = 1; index < this.tokens.length; index++) {
|
|
41562
|
-
if (this.tokens[index]
|
|
42465
|
+
if (isNativeBatchOption(this.tokens[index])) {
|
|
41563
42466
|
continue;
|
|
41564
42467
|
}
|
|
41565
42468
|
const row = parseBatchCommandArgument(this.tokens[index]).step;
|
|
@@ -41592,7 +42495,7 @@ var OperationPathBinding = class {
|
|
|
41592
42495
|
this.bindWebMcpParams();
|
|
41593
42496
|
}
|
|
41594
42497
|
bindBatch(stdin) {
|
|
41595
|
-
if (this.tokens.slice(1).some((token) => token
|
|
42498
|
+
if (this.tokens.slice(1).some((token) => !isNativeBatchOption(token))) {
|
|
41596
42499
|
this.bindRawBatchRows();
|
|
41597
42500
|
return { args: this.result, stdin };
|
|
41598
42501
|
}
|
|
@@ -42062,7 +42965,7 @@ var ElectronHostCoordinator = class {
|
|
|
42062
42965
|
return await withBrowserExecutionLocks({
|
|
42063
42966
|
identities,
|
|
42064
42967
|
signal: this.call.signal,
|
|
42065
|
-
deadline:
|
|
42968
|
+
deadline: performance.now() + this.call.executionTimeoutMs,
|
|
42066
42969
|
waitOnly: true
|
|
42067
42970
|
}, (signal) => this.execute(signal));
|
|
42068
42971
|
} catch (error) {
|
|
@@ -42636,6 +43539,11 @@ init_command_taxonomy();
|
|
|
42636
43539
|
init_session_state();
|
|
42637
43540
|
init_artifact_manifest();
|
|
42638
43541
|
init_read_confirmation();
|
|
43542
|
+
function withoutCommand(step) {
|
|
43543
|
+
const visible = { ...step };
|
|
43544
|
+
delete visible.command;
|
|
43545
|
+
return visible;
|
|
43546
|
+
}
|
|
42639
43547
|
var BrowserCommandResult = class {
|
|
42640
43548
|
runtime;
|
|
42641
43549
|
call;
|
|
@@ -42892,12 +43800,28 @@ var BrowserCommandResult = class {
|
|
|
42892
43800
|
throw new Error("The selected Pi branch changed before browser-state confirmation.");
|
|
42893
43801
|
}
|
|
42894
43802
|
} catch (error) {
|
|
42895
|
-
return this.persistenceFailure(error);
|
|
43803
|
+
return this.omitIndexedBatchCommands(this.persistenceFailure(error));
|
|
42896
43804
|
}
|
|
42897
43805
|
this.runtime.sessions.pages.applyBrowserRecord(finish);
|
|
42898
43806
|
this.runtime.artifacts.manifest = applyArtifactChanges(this.runtime.artifacts.manifest, finish.event.artifacts);
|
|
42899
43807
|
return void 0;
|
|
42900
43808
|
}
|
|
43809
|
+
omitIndexedBatchCommands(result) {
|
|
43810
|
+
const details = result.details;
|
|
43811
|
+
const tokens = extractUpstreamCommandTokens(this.call.toolArgs);
|
|
43812
|
+
if (!isRecord(details) || tokens[0] !== "batch" || !tokens.includes("--omit-command") || !Array.isArray(details.batchSteps)) {
|
|
43813
|
+
return result;
|
|
43814
|
+
}
|
|
43815
|
+
const failure = details.batchFailure;
|
|
43816
|
+
return {
|
|
43817
|
+
...result,
|
|
43818
|
+
details: {
|
|
43819
|
+
...details,
|
|
43820
|
+
batchSteps: details.batchSteps.map((step) => isRecord(step) ? withoutCommand(step) : step),
|
|
43821
|
+
...isRecord(failure) && isRecord(failure.failedStep) ? { batchFailure: { ...failure, failedStep: withoutCommand(failure.failedStep) } } : {}
|
|
43822
|
+
}
|
|
43823
|
+
};
|
|
43824
|
+
}
|
|
42901
43825
|
async complete() {
|
|
42902
43826
|
if (isRecord(this.result.details)) {
|
|
42903
43827
|
this.result.details.browserEventVersion = 1;
|
|
@@ -42906,12 +43830,13 @@ var BrowserCommandResult = class {
|
|
|
42906
43830
|
}
|
|
42907
43831
|
this.result.details.artifactManifest = invocationArtifactManifest(this.call.branch.isCurrent() ? this.runtime.artifacts.manifest : this.prepared.browserRunState.artifactManifest, this.dispatch.initialArtifactManifest, this.result.details);
|
|
42908
43832
|
}
|
|
42909
|
-
|
|
43833
|
+
const result = await applyAgentBrowserOutputPath({
|
|
42910
43834
|
cwd: this.call.operationCwd,
|
|
42911
43835
|
outputPath: this.call.outputPath,
|
|
42912
43836
|
preserveTextContent: Array.isArray(this.call.params.args) && isBooleanFlagEnabled(this.call.params.args, "--json"),
|
|
42913
43837
|
result: warnRecordingPersistence(this.runtime.recordings.dirty, this.result)
|
|
42914
43838
|
});
|
|
43839
|
+
return this.omitIndexedBatchCommands(result);
|
|
42915
43840
|
}
|
|
42916
43841
|
};
|
|
42917
43842
|
|
|
@@ -43205,7 +44130,7 @@ var BrowserCommandCoordinator = class {
|
|
|
43205
44130
|
}
|
|
43206
44131
|
deadline() {
|
|
43207
44132
|
const url = this.runtime.sessions.pages.get(this.key).tabTarget?.url;
|
|
43208
|
-
return
|
|
44133
|
+
return performance.now() + (this.call.params.timeoutMs ?? getCommandAwareProcessTimeoutMs(extractUpstreamCommandTokens(this.call.toolArgs), this.call.resolvedInput.toolStdin, url) ?? getAgentBrowserProcessTimeoutMs());
|
|
43209
44134
|
}
|
|
43210
44135
|
async runLocked() {
|
|
43211
44136
|
if (!this.needsIdentityLock()) {
|
|
@@ -43378,11 +44303,9 @@ var BrowserAdmission = class {
|
|
|
43378
44303
|
if (!this.canSelectNativeRoot(call)) {
|
|
43379
44304
|
return void 0;
|
|
43380
44305
|
}
|
|
43381
|
-
const root = process.env.PI_SUBAGENT_ROOT_SESSION_ID;
|
|
43382
|
-
const id = process.env.PI_SUBAGENT_CHILD === "1" && root !== void 0 && root !== "" ? root : call.ctx.sessionManager.getSessionId();
|
|
43383
44306
|
const profile = config.trustedBrowserDefaultProfile;
|
|
43384
44307
|
return {
|
|
43385
|
-
|
|
44308
|
+
sessionId: call.ctx.sessionManager.getSessionId(),
|
|
43386
44309
|
profile: profile?.policy === "always" && !/[\\/~]/.test(profile.name) ? profile.name : void 0,
|
|
43387
44310
|
executablePath: config.trustedBrowserExecutablePath
|
|
43388
44311
|
};
|
|
@@ -43522,6 +44445,7 @@ var BrowserCodeExecution = class {
|
|
|
43522
44445
|
runtime;
|
|
43523
44446
|
invocation;
|
|
43524
44447
|
operationCwd;
|
|
44448
|
+
/** A performance.now() timestamp bounding the whole cell, unaffected by wall-clock steps. */
|
|
43525
44449
|
deadline;
|
|
43526
44450
|
output = createBrowserCodeOutput();
|
|
43527
44451
|
nativeEnvironment = getAgentBrowserProcessEnvironment();
|
|
@@ -43535,7 +44459,7 @@ var BrowserCodeExecution = class {
|
|
|
43535
44459
|
this.runtime = runtime;
|
|
43536
44460
|
this.invocation = invocation;
|
|
43537
44461
|
this.operationCwd = operationCwd;
|
|
43538
|
-
this.deadline =
|
|
44462
|
+
this.deadline = performance.now() + (invocation.params.timeoutMs ?? AGENT_BROWSER_SCRIPT_DEFAULT_TIMEOUT_MS);
|
|
43539
44463
|
}
|
|
43540
44464
|
start() {
|
|
43541
44465
|
const { runtime, invocation } = this;
|
|
@@ -43579,10 +44503,8 @@ var BrowserCodeExecution = class {
|
|
|
43579
44503
|
includeProjectConfig: shouldIncludeProjectConfig(invocation.ctx)
|
|
43580
44504
|
});
|
|
43581
44505
|
const profile = config.trustedBrowserDefaultProfile;
|
|
43582
|
-
const root = process.env.PI_SUBAGENT_ROOT_SESSION_ID;
|
|
43583
|
-
const id = process.env.PI_SUBAGENT_CHILD === "1" && root !== void 0 && root !== "" ? root : invocation.ctx.sessionManager.getSessionId();
|
|
43584
44506
|
return {
|
|
43585
|
-
|
|
44507
|
+
sessionId: invocation.ctx.sessionManager.getSessionId(),
|
|
43586
44508
|
profile: profile?.policy === "always" && !/[\\/~]/.test(profile.name) ? profile.name : void 0,
|
|
43587
44509
|
executablePath: config.trustedBrowserExecutablePath
|
|
43588
44510
|
};
|
|
@@ -43652,7 +44574,7 @@ var BrowserCodeExecution = class {
|
|
|
43652
44574
|
params: {
|
|
43653
44575
|
args,
|
|
43654
44576
|
stdin: inner.stdin,
|
|
43655
|
-
timeoutMs: Math.min(inner.timeoutMs ?? this.
|
|
44577
|
+
timeoutMs: Math.min(inner.timeoutMs ?? this.remainingMs(), Math.max(1, this.remainingMs()))
|
|
43656
44578
|
},
|
|
43657
44579
|
signal: innerSignal,
|
|
43658
44580
|
ctx,
|
|
@@ -43668,11 +44590,15 @@ var BrowserCodeExecution = class {
|
|
|
43668
44590
|
}
|
|
43669
44591
|
return this.output.observe(result);
|
|
43670
44592
|
}
|
|
44593
|
+
/** Whole milliseconds left in the cell: inner calls and the script child take integer timeouts. */
|
|
44594
|
+
remainingMs() {
|
|
44595
|
+
return Math.ceil(this.deadline - performance.now());
|
|
44596
|
+
}
|
|
43671
44597
|
async runCell(signal, identity) {
|
|
43672
44598
|
const run = await runAgentBrowserScript({
|
|
43673
44599
|
code: this.invocation.params.code,
|
|
43674
44600
|
signal,
|
|
43675
|
-
timeoutMs: Math.max(1, this.
|
|
44601
|
+
timeoutMs: Math.max(1, this.remainingMs()),
|
|
43676
44602
|
emitImage: (image) => this.output.emitImage(image),
|
|
43677
44603
|
dispatch: (inner, innerSignal) => this.dispatch(inner, innerSignal, identity)
|
|
43678
44604
|
});
|
|
@@ -43724,7 +44650,7 @@ var BrowserCodeExecution = class {
|
|
|
43724
44650
|
}
|
|
43725
44651
|
async run() {
|
|
43726
44652
|
this.start();
|
|
43727
|
-
const timer = setTimeout(() => this.controller.abort(new DOMException("Browser code deadline exceeded.", "TimeoutError")), Math.max(0, this.
|
|
44653
|
+
const timer = setTimeout(() => this.controller.abort(new DOMException("Browser code deadline exceeded.", "TimeoutError")), Math.max(0, this.remainingMs()));
|
|
43728
44654
|
try {
|
|
43729
44655
|
const input = this.prepare();
|
|
43730
44656
|
if (input.status === "invalid") {
|