pi-agent-browser-native 0.9.4 → 0.9.5

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +58 -813
  3. package/dist/extensions/agent-browser/index.js +927 -883
  4. package/dist/extensions/agent-browser/lib/browser-execution-claims.js +5 -5
  5. package/dist/extensions/agent-browser/lib/config-policy.js +1 -1
  6. package/dist/extensions/agent-browser/lib/config-validation.js +21 -8
  7. package/dist/extensions/agent-browser/lib/config.js +1 -1
  8. package/dist/extensions/agent-browser/lib/electron/cdp.js +5 -1
  9. package/dist/extensions/agent-browser/lib/electron/cleanup.js +13 -47
  10. package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +1 -0
  11. package/dist/extensions/agent-browser/lib/electron/launch.js +12 -1
  12. package/dist/extensions/agent-browser/lib/fs-utils.js +1 -9
  13. package/dist/extensions/agent-browser/lib/input-modes/job.js +7 -4
  14. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +15 -3
  15. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +3 -2
  16. package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -23
  17. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +9 -8
  18. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +8 -0
  19. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +2 -2
  20. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +9 -0
  21. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +4 -2
  22. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +9 -11
  23. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +1 -0
  24. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +5 -6
  25. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +4 -2
  26. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +20 -2
  27. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +4 -2
  28. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +1 -1
  29. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +7 -2
  30. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +4 -1
  31. package/dist/extensions/agent-browser/lib/temp-root.js +22 -18
  32. package/dist/extensions/agent-browser/lib/temp.js +1 -1
  33. package/dist/extensions/agent-browser/lib/web-search-providers.js +0 -36
  34. package/dist/extensions/agent-browser/lib/web-search-request.js +20 -26
  35. package/dist/extensions/agent-browser/lib/web-search-schema.js +5 -5
  36. package/dist/extensions/agent-browser/lib/web-search.js +22 -4
  37. package/docs/ARCHITECTURE.md +3 -2
  38. package/docs/CODE_QUALITY.md +28 -3
  39. package/docs/COMMAND_REFERENCE.md +20 -20
  40. package/docs/ELECTRON.md +24 -2
  41. package/docs/REFERENCE.md +869 -0
  42. package/docs/RELEASE.md +9 -9
  43. package/docs/REQUIREMENTS.md +1 -1
  44. package/docs/SUPPORT_MATRIX.md +9 -8
  45. package/docs/TOOL_CONTRACT.md +13 -9
  46. package/docs/platform-smoke.md +3 -3
  47. package/package.json +3 -2
  48. package/scripts/config.mjs +23 -19
  49. package/scripts/doctor.mjs +2 -2
  50. package/scripts/platform-smoke/lease-evidence.mjs +2 -4
  51. package/scripts/platform-smoke/linux-image/Dockerfile +8 -2
  52. package/scripts/platform-smoke/targets.mjs +1 -5
@@ -5122,18 +5122,26 @@ async function cleanupSecureTempArtifacts(options = {}) {
5122
5122
  });
5123
5123
  });
5124
5124
  }
5125
- async function getSessionTempRoot() {
5126
- if (!sessionTempRootPromise) {
5127
- sessionTempRootPromise = (async () => {
5128
- const tempRoot2 = await mkdtemp(join3(tmpdir(), TEMP_ROOT_PREFIX));
5129
- await chmod2(tempRoot2, 448).catch(() => {
5130
- });
5131
- await writeSecureTempRootOwnershipMarker(tempRoot2);
5132
- ownedTempRoots.add(tempRoot2);
5133
- registerExitCleanup();
5134
- return tempRoot2;
5135
- })();
5125
+ async function allocateSessionTempRoot() {
5126
+ const tempRoot = await mkdtemp(join3(tmpdir(), TEMP_ROOT_PREFIX));
5127
+ try {
5128
+ await chmod2(tempRoot, 448).catch(() => {
5129
+ });
5130
+ await writeSecureTempRootOwnershipMarker(tempRoot);
5131
+ ownedTempRoots.add(tempRoot);
5132
+ registerExitCleanup();
5133
+ return tempRoot;
5134
+ } catch (error) {
5135
+ await rm2(tempRoot, { force: true, recursive: true }).catch(() => {
5136
+ });
5137
+ throw error;
5136
5138
  }
5139
+ }
5140
+ async function getSessionTempRoot() {
5141
+ sessionTempRootPromise ??= allocateSessionTempRoot().catch((error) => {
5142
+ sessionTempRootPromise = void 0;
5143
+ throw error;
5144
+ });
5137
5145
  const tempRoot = await sessionTempRootPromise;
5138
5146
  await refreshSecureTempRootLease(tempRoot).catch(() => {
5139
5147
  });
@@ -5237,7 +5245,10 @@ async function prunePersistentSessionArtifactsToBudget(sessionArtifactDir, addit
5237
5245
  if (protectedPaths.has(file.path)) {
5238
5246
  continue;
5239
5247
  }
5240
- await rm3(file.path, { force: true }).catch(() => void 0);
5248
+ const removed = await rm3(file.path, { force: true }).then(() => true, () => false);
5249
+ if (!removed) {
5250
+ continue;
5251
+ }
5241
5252
  evictedArtifacts.push({ mtimeMs: file.mtimeMs, path: file.path, sizeBytes: file.size });
5242
5253
  totalBytes -= file.size;
5243
5254
  if (totalBytes + additionalBytes <= maxBytes) {
@@ -8265,9 +8276,10 @@ function buildQaVisibleTextPredicate(text3) {
8265
8276
  if (style.display === "none" || style.visibility === "hidden" || Number(style.opacity) === 0) return false;
8266
8277
  return element.getClientRects().length > 0;
8267
8278
  };
8268
- const hasVisibleAncestors = (node) => {
8279
+ const ancestorsAllowVisibility = (node) => {
8269
8280
  for (let element = node.parentElement; element; element = element.parentElement) {
8270
- if (!isVisibleElement(element)) return false;
8281
+ const style = window.getComputedStyle(element);
8282
+ if (style.display === "none" || Number(style.opacity) === 0) return false;
8271
8283
  if (element === root) break;
8272
8284
  }
8273
8285
  return true;
@@ -8275,14 +8287,16 @@ function buildQaVisibleTextPredicate(text3) {
8275
8287
  const textWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
8276
8288
  let visitedText = 0;
8277
8289
  for (let node = textWalker.nextNode(); node && visitedText < 6000; node = textWalker.nextNode(), visitedText += 1) {
8278
- if (!hasVisibleAncestors(node)) continue;
8290
+ const parent = node.parentElement;
8291
+ if (!(parent instanceof HTMLElement) || skipTags.has(parent.tagName)) continue;
8292
+ if (window.getComputedStyle(parent).visibility === "hidden" || !ancestorsAllowVisibility(node)) continue;
8279
8293
  if (normalize(node.nodeValue).includes(expected)) return true;
8280
8294
  }
8281
8295
  const elementWalker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT);
8282
8296
  let visitedElements = 0;
8283
8297
  for (let node = elementWalker.nextNode(); node && visitedElements < 3000; node = elementWalker.nextNode(), visitedElements += 1) {
8284
8298
  const element = node;
8285
- if (!isVisibleElement(element) || !("value" in element)) continue;
8299
+ if (!isVisibleElement(element) || !ancestorsAllowVisibility(element) || !("value" in element)) continue;
8286
8300
  if (normalize(element.value).includes(expected)) return true;
8287
8301
  }
8288
8302
  return false;
@@ -8862,7 +8876,17 @@ function getFailedNetworkRequests(data, queryText) {
8862
8876
  });
8863
8877
  }
8864
8878
  }
8865
- return failed;
8879
+ const seenRequestIds = /* @__PURE__ */ new Set();
8880
+ return failed.filter(({ requestId: id }) => {
8881
+ if (id === void 0) {
8882
+ return true;
8883
+ }
8884
+ if (seenRequestIds.has(id)) {
8885
+ return false;
8886
+ }
8887
+ seenRequestIds.add(id);
8888
+ return true;
8889
+ });
8866
8890
  }
8867
8891
  function distinctNetworkCandidates(candidates) {
8868
8892
  const keys = /* @__PURE__ */ new Set();
@@ -8899,7 +8923,7 @@ function correlatesWithFailure(value, failedIds, failedUrls) {
8899
8923
  const url = typeof value.url === "string" ? value.url : void 0;
8900
8924
  return id !== void 0 && failedIds.has(id) || url !== void 0 && failedUrls.has(url);
8901
8925
  }
8902
- function observeInitiatorCandidates(data, failedRequests) {
8926
+ function observeInitiatorCandidates(data, failedRequests, queryText) {
8903
8927
  const failedIds = new Set(failedRequests.map((request) => request.requestId).filter((value) => value !== void 0));
8904
8928
  const failedUrls = new Set(failedRequests.map((request) => request.url).filter((value) => value !== void 0));
8905
8929
  const candidates = [];
@@ -8910,7 +8934,8 @@ function observeInitiatorCandidates(data, failedRequests) {
8910
8934
  if (!isRecord(value)) {
8911
8935
  continue;
8912
8936
  }
8913
- if (correlatesWithFailure(value, failedIds, failedUrls) || isFailedNetworkRecord(value)) {
8937
+ const url = typeof value.url === "string" ? value.url : void 0;
8938
+ if (networkRequestMatchesQuery(url, queryText) && (correlatesWithFailure(value, failedIds, failedUrls) || isFailedNetworkRecord(value))) {
8914
8939
  candidates.push(...initiatorCandidates(value));
8915
8940
  }
8916
8941
  }
@@ -9132,8 +9157,9 @@ function networkSummary(status, failedCount, candidateCount) {
9132
9157
  async function analyzeNetworkSourceLookupResults(data, compiled, cwd) {
9133
9158
  const { distinctNetworkCandidates: distinctNetworkCandidates2, getFailedNetworkRequests: getFailedNetworkRequests2, observeInitiatorCandidates: observeInitiatorCandidates2 } = await Promise.resolve().then(() => (init_lookup_network_evidence(), lookup_network_evidence_exports));
9134
9159
  const { scanWorkspaceRequests: scanWorkspaceRequests2 } = await Promise.resolve().then(() => (init_lookup_workspace(), lookup_workspace_exports));
9135
- const failedRequests = getFailedNetworkRequests2(data, compiled.query.url ?? compiled.query.filter);
9136
- const observed = observeInitiatorCandidates2(data, failedRequests);
9160
+ const queryText = compiled.query.filter ?? compiled.query.url;
9161
+ const failedRequests = getFailedNetworkRequests2(data, queryText);
9162
+ const observed = observeInitiatorCandidates2(data, failedRequests, queryText);
9137
9163
  const workspace = await scanWorkspaceRequests2(compiled.query, failedRequests, cwd);
9138
9164
  const candidates = distinctNetworkCandidates2([...observed, ...workspace.candidates]);
9139
9165
  const status = networkStatus(failedRequests.length, candidates.length);
@@ -11134,6 +11160,253 @@ var init_discovery_types = __esm({
11134
11160
  }
11135
11161
  });
11136
11162
 
11163
+ // dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js
11164
+ function storageTextContainsSecret(text3) {
11165
+ if (STORAGE_TOKEN_VALUE_PATTERN.test(text3) || STORAGE_SECRET_VALUE_WORD_PATTERN.test(text3) || STORAGE_EMAIL_VALUE_PATTERN.test(text3) || STORAGE_IDENTITY_VALUE_PATTERN.test(text3)) {
11166
+ return true;
11167
+ }
11168
+ if (storageTextIsSensitiveUrl(text3) || redactSensitiveText(text3) !== text3) {
11169
+ return true;
11170
+ }
11171
+ try {
11172
+ const parsed = JSON.parse(text3);
11173
+ return valueContainsStorageSecret(parsed);
11174
+ } catch {
11175
+ return false;
11176
+ }
11177
+ }
11178
+ function storageTextIsSensitiveUrl(text3) {
11179
+ try {
11180
+ const url = new URL(text3);
11181
+ return url.protocol === "http:" || url.protocol === "https:" || url.username.length > 0 || url.password.length > 0 || url.search.length > 0;
11182
+ } catch {
11183
+ return false;
11184
+ }
11185
+ }
11186
+ function valueContainsStorageSecret(value) {
11187
+ if (typeof value === "string") {
11188
+ const trimmed = value.trim();
11189
+ return trimmed.length > 0 && storageTextContainsSecret(trimmed);
11190
+ }
11191
+ if (Array.isArray(value)) {
11192
+ return value.some((item) => valueContainsStorageSecret(item));
11193
+ }
11194
+ if (!isRecord(value)) {
11195
+ return false;
11196
+ }
11197
+ return Object.entries(value).some(([key, entryValue]) => STORAGE_SECRET_KEY_PATTERN.test(key) || valueContainsStorageSecret(entryValue));
11198
+ }
11199
+ function shouldRevealStorageValue(key, value) {
11200
+ if (key === void 0 || key.length === 0 || STORAGE_SECRET_KEY_PATTERN.test(key) || !STORAGE_BENIGN_KEY_PATTERN.test(key)) {
11201
+ return false;
11202
+ }
11203
+ if (valueContainsStorageSecret(value)) {
11204
+ return false;
11205
+ }
11206
+ if (typeof value === "string") {
11207
+ return value.length <= STORAGE_VALUE_PREVIEW_MAX_CHARS;
11208
+ }
11209
+ return value === null || typeof value === "number" || typeof value === "boolean";
11210
+ }
11211
+ function formatStorageValue(key, value) {
11212
+ if (!shouldRevealStorageValue(key, value)) {
11213
+ return "[REDACTED]";
11214
+ }
11215
+ return typeof value === "string" ? redactModelFacingText(value) : stringifyModelFacing(value);
11216
+ }
11217
+ function storageRedactionReason(key) {
11218
+ return key !== void 0 && key.length > 0 && STORAGE_SECRET_KEY_PATTERN.test(key) ? "sensitive-key" : "sensitive-value";
11219
+ }
11220
+ function redactStorageEntryValue(item) {
11221
+ const key = getStringField(item, "key") ?? getStringField(item, "name");
11222
+ if (!Object.hasOwn(item, "value") || shouldRevealStorageValue(key, item.value)) {
11223
+ return redactSensitiveValue(item);
11224
+ }
11225
+ const redacted = redactSensitiveValue({ ...item, value: void 0 });
11226
+ if (!isRecord(redacted)) {
11227
+ throw new Error("Storage record redaction did not return a record");
11228
+ }
11229
+ return {
11230
+ ...redacted,
11231
+ value: "[REDACTED]",
11232
+ valueRedacted: true,
11233
+ valueRedactionReason: storageRedactionReason(key)
11234
+ };
11235
+ }
11236
+ function redactStorageField(owner, key, value) {
11237
+ if (key === "data" && isRecord(value)) {
11238
+ return Object.fromEntries(Object.entries(value).map(([storageKey, storageValue]) => [
11239
+ storageKey,
11240
+ shouldRevealStorageValue(storageKey, storageValue) ? redactSensitiveValue(storageValue) : "[REDACTED]"
11241
+ ]));
11242
+ }
11243
+ if ((key === "entries" || key === "items") && Array.isArray(value)) {
11244
+ return value.map((item) => isRecord(item) ? redactStorageEntryValue(item) : redactSensitiveValue(item));
11245
+ }
11246
+ if (key === "value") {
11247
+ const itemKey = getStringField(owner, "key") ?? getStringField(owner, "name");
11248
+ return shouldRevealStorageValue(itemKey, value) ? redactSensitiveValue(value) : "[REDACTED]";
11249
+ }
11250
+ return redactSensitiveValue(value);
11251
+ }
11252
+ function redactStorageData(value) {
11253
+ if (Array.isArray(value)) {
11254
+ return value.map((item) => redactStorageData(item));
11255
+ }
11256
+ if (!isRecord(value)) {
11257
+ return redactSensitiveValue(value);
11258
+ }
11259
+ const entries = Object.fromEntries(Object.entries(value).map(([key2, entryValue]) => [
11260
+ key2,
11261
+ redactStorageField(value, key2, entryValue)
11262
+ ]));
11263
+ const key = getStringField(value, "key") ?? getStringField(value, "name");
11264
+ if (Object.hasOwn(value, "value") && !shouldRevealStorageValue(key, value.value)) {
11265
+ entries.valueRedacted = true;
11266
+ entries.valueRedactionReason = storageRedactionReason(key);
11267
+ }
11268
+ return entries;
11269
+ }
11270
+ function formatStorageEntry(item, index) {
11271
+ if (!isRecord(item)) {
11272
+ return `${index + 1}. [REDACTED]`;
11273
+ }
11274
+ const rawKey = getStringField(item, "key") ?? getStringField(item, "name") ?? `(entry ${index + 1})`;
11275
+ const key = redactModelFacingText(rawKey);
11276
+ return Object.hasOwn(item, "value") ? `${key}: ${formatStorageValue(rawKey, item.value)}` : key;
11277
+ }
11278
+ function formatStorageMutationText(data, type) {
11279
+ const key = getStringField(data, "key");
11280
+ if (key !== void 0 && Object.hasOwn(data, "value")) {
11281
+ return `${type} ${redactModelFacingText(key)}: ${formatStorageValue(key, data.value)}`;
11282
+ }
11283
+ if (key !== void 0 && data.set === true) {
11284
+ return `${type} set: ${redactModelFacingText(key)}`;
11285
+ }
11286
+ return data.cleared === true || data.clear === true ? `${type} cleared.` : void 0;
11287
+ }
11288
+ function formatStorageText(data) {
11289
+ const type = getStringField(data, "type") ?? getStringField(data, "storage") ?? "storage";
11290
+ if (isRecord(data.data)) {
11291
+ const text3 = Object.entries(data.data).map(([key, value]) => `${redactModelFacingText(key)}: ${formatStorageValue(key, value)}`).join("\n");
11292
+ return text3.length > 0 ? text3 : `${type}: no entries.`;
11293
+ }
11294
+ const entries = getArrayField(data, "entries") ?? getArrayField(data, "items");
11295
+ if (entries) {
11296
+ return entries.length === 0 ? `${type}: no entries.` : entries.map(formatStorageEntry).join("\n");
11297
+ }
11298
+ return formatStorageMutationText(data, type);
11299
+ }
11300
+ function formatCookieRecordText(item, fallbackName) {
11301
+ const name = redactModelFacingText(getStringField(item, "name") ?? fallbackName);
11302
+ const domain = getStringField(item, "domain");
11303
+ const path = getStringField(item, "path");
11304
+ const flags = [
11305
+ item.httpOnly === true ? "httpOnly" : void 0,
11306
+ item.secure === true ? "secure" : void 0
11307
+ ].filter(Boolean).join(", ");
11308
+ const location = [domain, path].filter(Boolean).join("");
11309
+ return [
11310
+ name,
11311
+ location.length > 0 ? `(${redactModelFacingText(location)})` : void 0,
11312
+ flags.length > 0 ? `[${flags}]` : void 0
11313
+ ].filter(Boolean).join(" ");
11314
+ }
11315
+ function formatCookiesText(data) {
11316
+ const cookies = getArrayField(data, "cookies");
11317
+ if (cookies) {
11318
+ return cookies.length === 0 ? "No cookies." : cookies.map((item, index) => isRecord(item) ? formatCookieRecordText(item, `(cookie ${index + 1})`) : `${index + 1}. [REDACTED]`).join("\n");
11319
+ }
11320
+ if (getStringField(data, "name") !== void 0 || getStringField(data, "domain") !== void 0 || getStringField(data, "path") !== void 0 || Object.hasOwn(data, "value")) {
11321
+ return formatCookieRecordText(data, "cookie");
11322
+ }
11323
+ if (data.set === true) {
11324
+ return "Cookie set.";
11325
+ }
11326
+ return data.cleared === true || data.clear === true ? "Cookies cleared." : void 0;
11327
+ }
11328
+ var STORAGE_VALUE_PREVIEW_MAX_CHARS, STORAGE_SECRET_KEY_PATTERN, STORAGE_BENIGN_KEY_PATTERN, STORAGE_TOKEN_VALUE_PATTERN, STORAGE_SECRET_VALUE_WORD_PATTERN, STORAGE_EMAIL_VALUE_PATTERN, STORAGE_IDENTITY_VALUE_PATTERN;
11329
+ var init_diagnostic_storage = __esm({
11330
+ "dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js"() {
11331
+ "use strict";
11332
+ init_parsing();
11333
+ init_runtime();
11334
+ init_common();
11335
+ STORAGE_VALUE_PREVIEW_MAX_CHARS = 160;
11336
+ STORAGE_SECRET_KEY_PATTERN = /(?:access(?:_|-)?token|account|api(?:_|-)?key|auth(?:orization)?|bearer|client(?:_|-)?secret|cookie|credential|csrf|email|id(?:_|-)?token|jwt|pass(?:word)?|private(?:_|-)?key|profile|refresh(?:_|-)?token|secret|session|sid|sig(?:nature)?|token|user(?:name)?|x(?:_|-)?api(?:_|-)?key|xsrf)/i;
11337
+ STORAGE_BENIGN_KEY_PATTERN = /^(?:color(?:scheme)?|debug|dev|experiment|feature(?:flag)?|flag|language|layout|locale|mode|onboarding|sort|tab|theme|timezone|tour|variant|view)$/i;
11338
+ STORAGE_TOKEN_VALUE_PATTERN = /(?:\bBearer\s+[A-Za-z0-9._~-]+|\bBasic\s+[A-Za-z0-9+/=]+|^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$|(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_~+/=-]{32,})/;
11339
+ STORAGE_SECRET_VALUE_WORD_PATTERN = /(?:secret|token|password|passwd|bearer|credential|authorization|cookie|session[-_ ]?id)/i;
11340
+ STORAGE_EMAIL_VALUE_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
11341
+ STORAGE_IDENTITY_VALUE_PATTERN = /(?:^|[\s:=/_-])(?:account|profile|session|sid|user(?:id|name)?)(?:[\s:=/_-]|$)/i;
11342
+ }
11343
+ });
11344
+
11345
+ // dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js
11346
+ function redactStatefulValues(value) {
11347
+ if (Array.isArray(value)) {
11348
+ return value.map((item) => redactStatefulValues(item));
11349
+ }
11350
+ if (!isRecord(value)) {
11351
+ return redactSensitiveValue(value);
11352
+ }
11353
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
11354
+ key,
11355
+ key.toLowerCase() === "value" ? "[REDACTED]" : redactStatefulValues(entryValue)
11356
+ ]));
11357
+ }
11358
+ function storageTextKey(command) {
11359
+ const operation = command.commandTokens?.[2];
11360
+ if (operation === "get") {
11361
+ return command.commandTokens?.[3];
11362
+ }
11363
+ return operation === "set" || operation === "clear" ? void 0 : operation;
11364
+ }
11365
+ function redactStorageText(command, text3) {
11366
+ const key = storageTextKey(command);
11367
+ if (key !== void 0 && text3.startsWith(`${key}: `)) {
11368
+ const suffix = text3.endsWith("\n") ? "\n" : "";
11369
+ const value = text3.slice(key.length + 2, suffix.length > 0 ? -1 : void 0);
11370
+ return `${key}: ${formatStorageValue(key, value)}${suffix}`;
11371
+ }
11372
+ return text3.replace(/^([^\r\n]*?): ([^\r\n]*)/gm, (_line, entryKey, value) => `${entryKey}: ${formatStorageValue(entryKey, value)}`);
11373
+ }
11374
+ function redactNativeContextText(command, text3, stdin) {
11375
+ if (command.command === "batch") {
11376
+ const steps = getUpstreamEffectiveBatchSteps(command.commandTokens ?? ["batch"], stdin);
11377
+ const cookieRedacted = steps.some((step) => step[0] === "cookies") ? redactNativeContextText({ command: "cookies" }, text3) : text3;
11378
+ return steps.some((step) => step[0] === "storage") ? redactNativeContextText({ command: "storage" }, cookieRedacted) : cookieRedacted;
11379
+ }
11380
+ if (command.command === "cookies") {
11381
+ return text3.replace(/^([^=\r\n]*)=([^\r\n]*)/gm, "$1=[REDACTED]");
11382
+ }
11383
+ return command.command === "storage" ? redactStorageText(command, text3) : text3;
11384
+ }
11385
+ function redactPresentationData(command, data, stdin) {
11386
+ if (typeof data === "string") {
11387
+ return redactSensitiveText(redactNativeContextText(command, data, stdin));
11388
+ }
11389
+ if (command.command === "cookies") {
11390
+ return redactStatefulValues(data);
11391
+ }
11392
+ if (command.command === "storage") {
11393
+ return redactStorageData(data);
11394
+ }
11395
+ if (command.command === "state" && command.subcommand === "show") {
11396
+ return redactStatefulValues(data);
11397
+ }
11398
+ return redactSensitiveValue(data);
11399
+ }
11400
+ var init_diagnostic_redaction = __esm({
11401
+ "dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js"() {
11402
+ "use strict";
11403
+ init_parsing();
11404
+ init_batch_stdin();
11405
+ init_runtime();
11406
+ init_diagnostic_storage();
11407
+ }
11408
+ });
11409
+
11137
11410
  // dist/extensions/agent-browser/lib/results/next-actions.js
11138
11411
  function withOptionalNamespaceArgs(namespace, args) {
11139
11412
  return namespace !== void 0 && args[0] !== "--namespace" ? ["--namespace", namespace, ...args] : args;
@@ -11552,7 +11825,7 @@ function isSafeSameSnapshotFormBatchStep(step, refSnapshot) {
11552
11825
  return false;
11553
11826
  }
11554
11827
  }
11555
- function getBatchRefInvalidationMessage(commandTokens, stdin, refSnapshot) {
11828
+ function getBatchRefInvalidationFailure(commandTokens, stdin, refSnapshot) {
11556
11829
  if (commandTokens[0] !== "batch") {
11557
11830
  return;
11558
11831
  }
@@ -11563,7 +11836,11 @@ function getBatchRefInvalidationMessage(commandTokens, stdin, refSnapshot) {
11563
11836
  }
11564
11837
  const refIds = collectRefsFromTokens(step);
11565
11838
  if (refIds.length > 0 && isRefGuardedCommand(step[0]) && priorStepInvalidatesRefs) {
11566
- return `Batch step ${step[0]} uses page-scoped ref ${refIds.map((refId) => `@${refId}`).join(", ")} after an earlier batch step can navigate or mutate the page. Split the batch, run snapshot -i after the page-changing step, then retry with current refs.`;
11839
+ return {
11840
+ message: `Batch step ${step[0]} uses page-scoped ref ${refIds.map((refId) => `@${refId}`).join(", ")} after an earlier batch step can navigate or mutate the page. Split the batch, run snapshot -i after the page-changing step, then retry with current refs.`,
11841
+ refIds,
11842
+ snapshot: refSnapshot
11843
+ };
11567
11844
  }
11568
11845
  if (isRefInvalidatingBatchCommand(step) && !isSafeSameSnapshotFormBatchStep(step, refSnapshot)) {
11569
11846
  priorStepInvalidatesRefs = true;
@@ -11608,13 +11885,9 @@ function buildStaleRefPreflight(facts) {
11608
11885
  includeRefsAfterBatchSnapshot: true
11609
11886
  }))
11610
11887
  ] : guardedRefIds;
11611
- const batchInvalidationMessage = getBatchRefInvalidationMessage(facts.commandTokens, facts.stdin, facts.refSnapshot);
11612
- if (batchInvalidationMessage !== void 0 && batchInvalidationMessage.length > 0 && guardedRefIds.length > 0) {
11613
- return {
11614
- message: batchInvalidationMessage,
11615
- refIds: guardedRefIds,
11616
- snapshot: facts.refSnapshot
11617
- };
11888
+ const batchInvalidationFailure = getBatchRefInvalidationFailure(facts.commandTokens, facts.stdin, facts.refSnapshot);
11889
+ if (batchInvalidationFailure) {
11890
+ return batchInvalidationFailure;
11618
11891
  }
11619
11892
  if (usedRefIds.length === 0) {
11620
11893
  return;
@@ -14004,6 +14277,364 @@ var init_action_recommendations = __esm({
14004
14277
  }
14005
14278
  });
14006
14279
 
14280
+ // dist/extensions/agent-browser/lib/electron/cdp.js
14281
+ function asString(value) {
14282
+ return typeof value === "string" && value.trim().length > 0 ? value : void 0;
14283
+ }
14284
+ function parseCdpVersion(value) {
14285
+ if (!isRecord(value)) {
14286
+ return void 0;
14287
+ }
14288
+ const browser = asString(value.Browser) ?? asString(value.browser);
14289
+ if (browser === void 0) {
14290
+ return void 0;
14291
+ }
14292
+ return {
14293
+ browser,
14294
+ protocolVersion: asString(value["Protocol-Version"]) ?? asString(value.protocolVersion),
14295
+ userAgent: asString(value["User-Agent"]) ?? asString(value.userAgent),
14296
+ v8Version: asString(value["V8-Version"]) ?? asString(value.v8Version),
14297
+ webKitVersion: asString(value["WebKit-Version"]) ?? asString(value.webKitVersion),
14298
+ webSocketDebuggerUrl: asString(value.webSocketDebuggerUrl)
14299
+ };
14300
+ }
14301
+ function parseCdpTargets(value) {
14302
+ if (!Array.isArray(value)) {
14303
+ return [];
14304
+ }
14305
+ return value.filter(isRecord).map((target) => ({
14306
+ id: asString(target.id),
14307
+ title: asString(target.title),
14308
+ type: asString(target.type),
14309
+ url: asString(target.url),
14310
+ webSocketDebuggerUrl: asString(target.webSocketDebuggerUrl)
14311
+ }));
14312
+ }
14313
+ async function fetchCdpJson(url, signal) {
14314
+ const controller = new AbortController();
14315
+ const timeout = setTimeout(() => controller.abort(), ELECTRON_CDP_FETCH_TIMEOUT_MS);
14316
+ try {
14317
+ const response = await fetch(url, {
14318
+ signal: signal ? AbortSignal.any([signal, controller.signal]) : controller.signal
14319
+ });
14320
+ if (!response.ok) {
14321
+ return void 0;
14322
+ }
14323
+ return await response.json();
14324
+ } catch {
14325
+ return void 0;
14326
+ } finally {
14327
+ clearTimeout(timeout);
14328
+ }
14329
+ }
14330
+ function boundElectronProbeString(value, maxLength = 240) {
14331
+ const trimmed = value?.trim();
14332
+ if (trimmed === void 0 || trimmed.length === 0) {
14333
+ return void 0;
14334
+ }
14335
+ return trimmed.length > maxLength ? `${trimmed.slice(0, Math.max(0, maxLength - 3))}...` : trimmed;
14336
+ }
14337
+ var ELECTRON_CDP_FETCH_TIMEOUT_MS;
14338
+ var init_cdp = __esm({
14339
+ "dist/extensions/agent-browser/lib/electron/cdp.js"() {
14340
+ "use strict";
14341
+ init_parsing();
14342
+ ELECTRON_CDP_FETCH_TIMEOUT_MS = 1e3;
14343
+ }
14344
+ });
14345
+
14346
+ // dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js
14347
+ function redactExactSensitiveText(text3, sensitiveValues) {
14348
+ let redacted = text3;
14349
+ for (const value of sensitiveValues) {
14350
+ redacted = redacted.split(value).join("[REDACTED]");
14351
+ }
14352
+ return redacted;
14353
+ }
14354
+ function redactExactSensitiveValue(value, sensitiveValues) {
14355
+ if (sensitiveValues.length === 0) {
14356
+ return value;
14357
+ }
14358
+ if (typeof value === "string") {
14359
+ return redactExactSensitiveText(value, sensitiveValues);
14360
+ }
14361
+ if (Array.isArray(value)) {
14362
+ const entries = value;
14363
+ return entries.map((item) => redactExactSensitiveValue(item, sensitiveValues));
14364
+ }
14365
+ if (!isRecord(value)) {
14366
+ return value;
14367
+ }
14368
+ return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
14369
+ key,
14370
+ redactExactSensitiveValue(entryValue, sensitiveValues)
14371
+ ]));
14372
+ }
14373
+ function redactToolDetails(details, sensitiveValues) {
14374
+ const redacted = redactSensitiveValue(redactExactSensitiveValue(details, sensitiveValues));
14375
+ if (!isRecord(redacted)) {
14376
+ throw new Error("Browser result details must remain an object after redaction.");
14377
+ }
14378
+ return redacted;
14379
+ }
14380
+ function redactRecoveryHint(recoveryHint) {
14381
+ if (!recoveryHint) {
14382
+ return void 0;
14383
+ }
14384
+ const exampleArgs = redactInvocationArgs(recoveryHint.exampleArgs);
14385
+ return {
14386
+ ...recoveryHint,
14387
+ exampleArgs,
14388
+ exampleParams: { ...recoveryHint.exampleParams, args: exampleArgs }
14389
+ };
14390
+ }
14391
+ function buildJsonVisibleContent(options) {
14392
+ const { error, presentation, succeeded, warnings } = options;
14393
+ const payload = projectAgentBrowserObservation({
14394
+ ...presentation,
14395
+ ...options.details,
14396
+ error,
14397
+ warnings: warnings !== void 0 && warnings.length > 0 ? warnings : void 0
14398
+ }, succeeded);
14399
+ const images = presentation.content.filter((item) => item.type === "image");
14400
+ return [{ type: "text", text: JSON.stringify(payload, null, 2) }, ...images];
14401
+ }
14402
+ function warningLines(text3) {
14403
+ return text3 === void 0 || text3.length === 0 ? void 0 : [text3];
14404
+ }
14405
+ function contentWithWarnings(options) {
14406
+ if (options.userRequestedJson && !options.plainTextInspection) {
14407
+ return buildJsonVisibleContent({
14408
+ error: options.presentationEnvelope?.error,
14409
+ presentation: options.presentation,
14410
+ succeeded: options.succeeded,
14411
+ warnings: warningLines(options.warningText)
14412
+ });
14413
+ }
14414
+ const content = [...options.presentation.content];
14415
+ if (options.warningText === void 0 || options.warningText.length === 0 || options.userRequestedJson) {
14416
+ return content;
14417
+ }
14418
+ if (content[0]?.type === "text") {
14419
+ content[0] = { ...content[0], text: `${options.warningText}
14420
+
14421
+ ${content[0].text}` };
14422
+ } else {
14423
+ content.unshift({ type: "text", text: options.warningText });
14424
+ }
14425
+ return content;
14426
+ }
14427
+ function buildRedactedPresentationContent(options) {
14428
+ return contentWithWarnings(options).map((item) => {
14429
+ if (item.type !== "text") {
14430
+ return item;
14431
+ }
14432
+ const text3 = options.userRequestedJson && !options.plainTextInspection ? JSON.stringify(redactExactSensitiveValue(JSON.parse(item.text), options.exactSensitiveValues), null, 2) : redactSensitiveText(redactExactSensitiveText(item.text, options.exactSensitiveValues));
14433
+ return { type: "text", text: text3 };
14434
+ });
14435
+ }
14436
+ function readJsonWarnings(content) {
14437
+ if (content[0]?.type !== "text") {
14438
+ return void 0;
14439
+ }
14440
+ const prior = JSON.parse(content[0].text);
14441
+ if (!isRecord(prior) || !Array.isArray(prior.warnings)) {
14442
+ return void 0;
14443
+ }
14444
+ const warnings = prior.warnings;
14445
+ return warnings;
14446
+ }
14447
+ var init_final_result_redaction = __esm({
14448
+ "dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js"() {
14449
+ "use strict";
14450
+ init_parsing();
14451
+ init_runtime_redaction();
14452
+ init_content();
14453
+ }
14454
+ });
14455
+
14456
+ // dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js
14457
+ function presentElectronManagedSessionTarget(target) {
14458
+ return {
14459
+ ...target,
14460
+ title: boundElectronProbeString(target.title, 160),
14461
+ url: boundElectronProbeString(target.url, 300)
14462
+ };
14463
+ }
14464
+ function getElectronLaunchFailureCategory(failure) {
14465
+ switch (failure.reason) {
14466
+ case "aborted":
14467
+ return "aborted";
14468
+ case "policy-blocked":
14469
+ return "policy-blocked";
14470
+ case "timeout":
14471
+ return "timeout";
14472
+ case "non-electron-target":
14473
+ return "validation-error";
14474
+ case "port-not-found":
14475
+ case "single-instance-conflict":
14476
+ case "spawn-error":
14477
+ return "upstream-error";
14478
+ }
14479
+ }
14480
+ function pidState(pidAlive) {
14481
+ if (pidAlive === void 0) {
14482
+ return "state unknown";
14483
+ }
14484
+ return pidAlive ? "alive before cleanup" : "not alive before cleanup";
14485
+ }
14486
+ function formatProcessDiagnostics(diagnostics) {
14487
+ const lines = [];
14488
+ if (diagnostics.pid !== void 0) {
14489
+ lines.push(`- PID: ${diagnostics.pid} (${pidState(diagnostics.pidAlive)}).`);
14490
+ }
14491
+ if (diagnostics.exitCode !== void 0 || diagnostics.exitSignal !== void 0) {
14492
+ const exitParts = [
14493
+ diagnostics.exitCode !== void 0 ? `code ${String(diagnostics.exitCode)}` : void 0,
14494
+ diagnostics.exitSignal !== void 0 && diagnostics.exitSignal !== null && diagnostics.exitSignal.length > 0 ? `signal ${diagnostics.exitSignal}` : void 0
14495
+ ].filter(Boolean).join(", ");
14496
+ lines.push(`- Process exit: ${exitParts.length > 0 ? exitParts : "not observed before cleanup"}.`);
14497
+ }
14498
+ return lines;
14499
+ }
14500
+ function formatActivePort(activePort) {
14501
+ const error = activePort.error !== void 0 && activePort.error.length > 0 ? ` (${activePort.error})` : "";
14502
+ let state;
14503
+ if (activePort.port !== void 0 && activePort.port !== 0) {
14504
+ state = `found port ${activePort.port}`;
14505
+ } else {
14506
+ state = activePort.found ? `found but invalid${error}` : `missing${error}`;
14507
+ }
14508
+ return `- DevToolsActivePort: ${state} at ${activePort.path}.`;
14509
+ }
14510
+ function formatConnectionDiagnostics(diagnostics) {
14511
+ const lines = [];
14512
+ if (diagnostics.userDataDir !== void 0 && diagnostics.userDataDir.length > 0) {
14513
+ lines.push(`- Wrapper profile: ${diagnostics.userDataDir}`);
14514
+ }
14515
+ if (diagnostics.devToolsActivePort) {
14516
+ lines.push(formatActivePort(diagnostics.devToolsActivePort));
14517
+ }
14518
+ if (diagnostics.cdpVersionReached === false) {
14519
+ lines.push("- CDP /json/version: did not return a valid payload before timeout.");
14520
+ }
14521
+ if (diagnostics.timeoutMs !== void 0 || diagnostics.elapsedMs !== void 0) {
14522
+ lines.push(`- Timing: ${diagnostics.elapsedMs ?? "unknown"}ms elapsed${diagnostics.timeoutMs !== void 0 ? ` of ${diagnostics.timeoutMs}ms timeout` : ""}.`);
14523
+ }
14524
+ if (!diagnostics.outputCaptured) {
14525
+ lines.push("- App stdout/stderr: not captured by this wrapper launch path.");
14526
+ }
14527
+ return lines;
14528
+ }
14529
+ function formatElectronLaunchFailureDiagnostics(failure) {
14530
+ const diagnostics = failure?.diagnostics;
14531
+ if (!diagnostics) {
14532
+ return void 0;
14533
+ }
14534
+ const lines = [
14535
+ "Electron launch diagnostics:",
14536
+ ...formatProcessDiagnostics(diagnostics),
14537
+ ...formatConnectionDiagnostics(diagnostics)
14538
+ ];
14539
+ if (failure.reason !== "aborted") {
14540
+ lines.push("Retry guidance: increase electron.timeoutMs, try targetType:'any', pass an explicit appPath/executablePath, quit any already-running singleton instance, then retry launch.");
14541
+ }
14542
+ return lines.join("\n");
14543
+ }
14544
+ function buildElectronHostFailureResult(options) {
14545
+ const text3 = [
14546
+ options.errorText,
14547
+ formatElectronLaunchFailureDiagnostics(options.launchFailure),
14548
+ options.launchFailure?.cleanupError !== void 0 && options.launchFailure.cleanupError.length > 0 ? `Electron launch cleanup warning: ${options.launchFailure.cleanupError}` : void 0
14549
+ ].filter((item) => item !== void 0 && item.length > 0).join("\n");
14550
+ const details = {
14551
+ args: [],
14552
+ compiledElectron: options.compiledElectron,
14553
+ electron: {
14554
+ action: options.compiledElectron.action,
14555
+ error: options.errorText,
14556
+ failure: options.launchFailure,
14557
+ status: options.status ?? "failed"
14558
+ },
14559
+ managedSessionOutcome: options.managedSessionOutcome,
14560
+ ...buildAgentBrowserResultCategoryDetails({
14561
+ args: [],
14562
+ errorText: options.errorText,
14563
+ failureCategory: options.failureCategory,
14564
+ succeeded: false,
14565
+ timedOut: options.failureCategory === "timeout"
14566
+ }),
14567
+ summary: options.errorText
14568
+ };
14569
+ return {
14570
+ content: [{ type: "text", text: redactSensitiveText(text3) }],
14571
+ details: redactToolDetails(details, []),
14572
+ isError: true
14573
+ };
14574
+ }
14575
+ function formatElectronTargetLines(targets, limit = 8) {
14576
+ const shownTargets = targets.slice(0, limit);
14577
+ const lines = shownTargets.map((target) => {
14578
+ const typeTitle = [target.type, target.title].filter(Boolean).join(" ");
14579
+ const fallback = target.id === void 0 || target.id.length === 0 ? "target" : target.id;
14580
+ const label = typeTitle.length > 0 ? typeTitle : fallback;
14581
+ return `- ${label}${target.url !== void 0 && target.url.length > 0 ? ` \u2014 ${target.url}` : ""}`;
14582
+ });
14583
+ if (targets.length > shownTargets.length) {
14584
+ lines.push(`- ... ${targets.length - shownTargets.length} more target(s) omitted`);
14585
+ }
14586
+ return lines;
14587
+ }
14588
+ function formatSnapshotHandoff(handoff) {
14589
+ if (handoff.refSnapshot && handoff.refSnapshot.refIds.length > 0) {
14590
+ const retries = handoff.snapshotRetryCount;
14591
+ return `Snapshot handoff: ${handoff.refSnapshot.refIds.length} interactive ref(s)${retries !== void 0 && retries !== 0 ? ` after ${retries} retry attempt(s)` : ""}.`;
14592
+ }
14593
+ return "Snapshot handoff: no interactive refs returned after a short readiness retry; run snapshot -i once more before assuming the Electron UI is unusable.";
14594
+ }
14595
+ function formatHandoffText(handoff) {
14596
+ switch (handoff?.handoff) {
14597
+ case "snapshot":
14598
+ return formatSnapshotHandoff(handoff);
14599
+ case "tabs":
14600
+ return "Tabs handoff completed: safer diagnostic starting point; no interactive refs were captured.";
14601
+ case "connect":
14602
+ return "Connect handoff completed: run snapshot -i before using interactive refs.";
14603
+ case void 0:
14604
+ return void 0;
14605
+ }
14606
+ }
14607
+ function formatElectronLaunchText(options) {
14608
+ const lines = [
14609
+ `Electron launch: ${options.record.appName} attached as ${options.record.sessionName ?? "managed session"} (launchId ${options.record.launchId}, port ${options.record.port}).`,
14610
+ `Identifiers: launchId ${options.record.launchId} for electron.status/electron.cleanup/electron.probe; sessionName ${options.record.sessionName ?? "not attached"} for browser snapshot/tab commands.`,
14611
+ "Profile note: electron.launch starts an isolated temporary profile; it does not reuse the app's normal signed-in profile or attach to an already-running authenticated app.",
14612
+ "For already-authenticated desktop app content, do not stop here: if host tools are allowed and the app is not running, launch the normal app with --remote-debugging-port=<port>, verify the port, then run agent_browser connect <port>; if it is already running without a debug port, ask before relaunching it.",
14613
+ ...formatElectronTargetLines(options.targets)
14614
+ ];
14615
+ const handoffText = formatHandoffText(options.handoff);
14616
+ if (handoffText !== void 0) {
14617
+ lines.push(handoffText);
14618
+ }
14619
+ lines.push(`Cleanup: use details.nextActions cleanup-electron-launch or call electron.cleanup with launchId ${options.record.launchId} when finished.`);
14620
+ if (options.handoff?.error !== void 0 && options.handoff.error.length > 0) {
14621
+ lines.push(`Handoff warning: ${options.handoff.error}`);
14622
+ }
14623
+ if (options.upstreamText.trim().length > 0) {
14624
+ lines.push("", options.upstreamText.trim());
14625
+ }
14626
+ return lines.join("\n");
14627
+ }
14628
+ var init_final_result_electron = __esm({
14629
+ "dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js"() {
14630
+ "use strict";
14631
+ init_cdp();
14632
+ init_categories();
14633
+ init_runtime_redaction();
14634
+ init_final_result_redaction();
14635
+ }
14636
+ });
14637
+
14007
14638
  // dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js
14008
14639
  function isLiveElectronRendererTarget(target) {
14009
14640
  const normalizedUrl = normalizeComparableUrl(target.url);
@@ -14099,15 +14730,16 @@ function buildElectronSessionMismatch(options) {
14099
14730
  return;
14100
14731
  }
14101
14732
  const nextActions = buildElectronMismatchNextActions(options.record, liveTarget);
14733
+ const managedSession = presentElectronManagedSessionTarget(options.managedSession);
14102
14734
  return {
14103
14735
  launchId: options.record.launchId,
14104
14736
  liveTarget,
14105
- managedSession: options.managedSession,
14737
+ managedSession,
14106
14738
  nextActionIds: nextActions.map((action) => action.id),
14107
14739
  reason,
14108
14740
  sessionName: options.record.sessionName,
14109
14741
  statusTargets: options.statusTargets,
14110
- summary: describeElectronMismatch(options.managedSession, options.record, liveTarget, reason)
14742
+ summary: describeElectronMismatch(managedSession, options.record, liveTarget, reason)
14111
14743
  };
14112
14744
  }
14113
14745
  function formatElectronSessionMismatchText(mismatch) {
@@ -14209,6 +14841,7 @@ var init_session_state_electron = __esm({
14209
14841
  init_action_recommendations();
14210
14842
  init_session_page_state();
14211
14843
  init_session_state_refs();
14844
+ init_final_result_electron();
14212
14845
  }
14213
14846
  });
14214
14847
 
@@ -14307,68 +14940,6 @@ var init_session_state = __esm({
14307
14940
  }
14308
14941
  });
14309
14942
 
14310
- // dist/extensions/agent-browser/lib/electron/cdp.js
14311
- function asString(value) {
14312
- return typeof value === "string" && value.trim().length > 0 ? value : void 0;
14313
- }
14314
- function parseCdpVersion(value) {
14315
- if (!isRecord(value)) {
14316
- return void 0;
14317
- }
14318
- return {
14319
- browser: asString(value.Browser) ?? asString(value.browser),
14320
- protocolVersion: asString(value["Protocol-Version"]) ?? asString(value.protocolVersion),
14321
- userAgent: asString(value["User-Agent"]) ?? asString(value.userAgent),
14322
- v8Version: asString(value["V8-Version"]) ?? asString(value.v8Version),
14323
- webKitVersion: asString(value["WebKit-Version"]) ?? asString(value.webKitVersion),
14324
- webSocketDebuggerUrl: asString(value.webSocketDebuggerUrl)
14325
- };
14326
- }
14327
- function parseCdpTargets(value) {
14328
- if (!Array.isArray(value)) {
14329
- return [];
14330
- }
14331
- return value.filter(isRecord).map((target) => ({
14332
- id: asString(target.id),
14333
- title: asString(target.title),
14334
- type: asString(target.type),
14335
- url: asString(target.url),
14336
- webSocketDebuggerUrl: asString(target.webSocketDebuggerUrl)
14337
- }));
14338
- }
14339
- async function fetchCdpJson(url, signal) {
14340
- const controller = new AbortController();
14341
- const timeout = setTimeout(() => controller.abort(), ELECTRON_CDP_FETCH_TIMEOUT_MS);
14342
- try {
14343
- const response = await fetch(url, {
14344
- signal: signal ? AbortSignal.any([signal, controller.signal]) : controller.signal
14345
- });
14346
- if (!response.ok) {
14347
- return void 0;
14348
- }
14349
- return await response.json();
14350
- } catch {
14351
- return void 0;
14352
- } finally {
14353
- clearTimeout(timeout);
14354
- }
14355
- }
14356
- function boundElectronProbeString(value, maxLength = 240) {
14357
- const trimmed = value?.trim();
14358
- if (trimmed === void 0 || trimmed.length === 0) {
14359
- return void 0;
14360
- }
14361
- return trimmed.length > maxLength ? `${trimmed.slice(0, Math.max(0, maxLength - 3))}...` : trimmed;
14362
- }
14363
- var ELECTRON_CDP_FETCH_TIMEOUT_MS;
14364
- var init_cdp = __esm({
14365
- "dist/extensions/agent-browser/lib/electron/cdp.js"() {
14366
- "use strict";
14367
- init_parsing();
14368
- ELECTRON_CDP_FETCH_TIMEOUT_MS = 1e3;
14369
- }
14370
- });
14371
-
14372
14943
  // dist/extensions/agent-browser/lib/electron/launch-types.js
14373
14944
  var ELECTRON_LAUNCH_RECORD_VERSION, ELECTRON_PROFILE_DIR_PREFIX;
14374
14945
  var init_launch_types = __esm({
@@ -14380,7 +14951,7 @@ var init_launch_types = __esm({
14380
14951
  });
14381
14952
 
14382
14953
  // dist/extensions/agent-browser/lib/fs-utils.js
14383
- import { access, stat as stat9 } from "node:fs/promises";
14954
+ import { access } from "node:fs/promises";
14384
14955
  async function pathExists(path) {
14385
14956
  try {
14386
14957
  await access(path);
@@ -14396,10 +14967,7 @@ var init_fs_utils = __esm({
14396
14967
  });
14397
14968
 
14398
14969
  // dist/extensions/agent-browser/lib/electron/cleanup.js
14399
- import { execFile as execFile2 } from "node:child_process";
14400
14970
  import { lstat as lstat2, rm as rm7 } from "node:fs/promises";
14401
- import { win32 as win323 } from "node:path";
14402
- import { promisify as promisify2 } from "node:util";
14403
14971
  function sleep(ms) {
14404
14972
  return new Promise((resolve19) => {
14405
14973
  setTimeout(resolve19, ms);
@@ -14457,39 +15025,16 @@ async function waitForProcessExit(child, pid, deadlineMs) {
14457
15025
  }
14458
15026
  return hasProcessExited(child, pid);
14459
15027
  }
14460
- async function readPidCommandLine(pid) {
14461
- if (!Number.isSafeInteger(pid) || pid <= 0) {
14462
- return void 0;
14463
- }
14464
- try {
14465
- const systemRoot = process.env.SystemRoot;
14466
- const windowsRoot = systemRoot !== void 0 && systemRoot.length > 0 && win323.isAbsolute(systemRoot) ? systemRoot : "C:\\Windows";
14467
- const file = process.platform === "win32" ? win323.join(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : "ps";
14468
- const args = process.platform === "win32" ? [
14469
- "-NoProfile",
14470
- "-NonInteractive",
14471
- "-Command",
14472
- `[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new(); $p = [wmi]"Win32_Process.Handle='${pid}'"; [Console]::WriteLine($p.CommandLine)`
14473
- ] : ["-ww", "-p", String(pid), "-o", "command="];
14474
- const { stdout } = await execFileAsync(file, args, {
14475
- timeout: RESTORED_PROCESS_COMMAND_TIMEOUT_MS
14476
- });
14477
- const commandLine = stdout.trim();
14478
- return commandLine.length === 0 ? void 0 : commandLine;
14479
- } catch {
14480
- return void 0;
14481
- }
14482
- }
14483
- function restoredLaunchCommandMatchesRecord(record, commandLine) {
14484
- return commandLine?.includes(`--user-data-dir=${record.userDataDir}`) === true;
14485
- }
14486
15028
  async function getRestoredProcessVerificationError(record) {
14487
- const commandLine = record.pid === void 0 ? void 0 : await readPidCommandLine(record.pid);
14488
- if (commandLine === void 0 || commandLine.length === 0) {
14489
- return `PID ${String(record.pid)} is alive, but this session has no tracked child handle and its command line could not be inspected; refusing to signal a restored PID that may have been reused.`;
15029
+ if (record.startIdentity === void 0 || record.startIdentity.length === 0) {
15030
+ return `PID ${String(record.pid)} is alive, but this session has no tracked child handle or recorded start identity; refusing to signal a restored PID that may have been reused.`;
14490
15031
  }
14491
- if (!restoredLaunchCommandMatchesRecord(record, commandLine)) {
14492
- return `PID ${String(record.pid)} is alive, but this session has no tracked child handle and its command line does not include wrapper-owned user data dir ${record.userDataDir}; refusing to signal a restored PID that may have been reused.`;
15032
+ const currentIdentity = record.pid === void 0 ? void 0 : await readProcessStartIdentity(record.pid);
15033
+ if (currentIdentity === void 0) {
15034
+ 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.`;
15035
+ }
15036
+ if (!processStartIdentitiesMatch(record.startIdentity, currentIdentity)) {
15037
+ 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.`;
14493
15038
  }
14494
15039
  return void 0;
14495
15040
  }
@@ -14542,6 +15087,10 @@ async function cleanupRestoredProcess(record, deadlineMs) {
14542
15087
  if (await waitForProcessExit(void 0, record.pid, deadlineMs)) {
14543
15088
  return { resource: "process", state: "removed" };
14544
15089
  }
15090
+ const killVerificationError = await getRestoredProcessVerificationError(record);
15091
+ if (killVerificationError !== void 0) {
15092
+ return { error: killVerificationError, resource: "process", state: "failed" };
15093
+ }
14545
15094
  signalRestoredLaunchProcess(record, "SIGKILL");
14546
15095
  if (await waitForProcessExit(void 0, record.pid, Date.now() + 1e3)) {
14547
15096
  return { resource: "process", state: "removed" };
@@ -14651,7 +15200,7 @@ async function cleanupElectronLaunchResources(options) {
14651
15200
  summary: summary.summary
14652
15201
  };
14653
15202
  }
14654
- var ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS, ELECTRON_CLEANUP_POLL_INTERVAL_MS, RESTORED_PROCESS_COMMAND_TIMEOUT_MS, execFileAsync;
15203
+ var ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS, ELECTRON_CLEANUP_POLL_INTERVAL_MS;
14655
15204
  var init_cleanup = __esm({
14656
15205
  "dist/extensions/agent-browser/lib/electron/cleanup.js"() {
14657
15206
  "use strict";
@@ -14659,12 +15208,11 @@ var init_cleanup = __esm({
14659
15208
  init_launch_types();
14660
15209
  init_fs_utils();
14661
15210
  init_parsing();
15211
+ init_process_identity();
14662
15212
  init_text();
14663
15213
  init_temp();
14664
15214
  ELECTRON_CLEANUP_DEFAULT_TIMEOUT_MS = 5e3;
14665
15215
  ELECTRON_CLEANUP_POLL_INTERVAL_MS = 100;
14666
- RESTORED_PROCESS_COMMAND_TIMEOUT_MS = 1e3;
14667
- execFileAsync = promisify2(execFile2);
14668
15216
  }
14669
15217
  });
14670
15218
 
@@ -15123,8 +15671,8 @@ async function publishTicket(claim) {
15123
15671
  await rename2(candidate, join20(claim.path, LOCK_TICKET_FILE));
15124
15672
  return ticket.ticket;
15125
15673
  }
15126
- function acquisitionExpired(budget) {
15127
- return budget.signal?.aborted === true || budget.deadline !== void 0 && Date.now() >= budget.deadline;
15674
+ function acquisitionCancelled(budget) {
15675
+ return budget.signal?.aborted === true;
15128
15676
  }
15129
15677
  async function waitForTurn(claim, ticket, budget, deadline) {
15130
15678
  while (budget.signal?.aborted !== true) {
@@ -15138,7 +15686,7 @@ async function waitForTurn(claim, ticket, budget, deadline) {
15138
15686
  }
15139
15687
  if (!await anyPredecessorBlocks(claims, own, budget)) {
15140
15688
  await cleanDeadPolicyArtifacts(claim.directory, budget);
15141
- return !acquisitionExpired(budget);
15689
+ return !acquisitionCancelled(budget);
15142
15690
  }
15143
15691
  if (Date.now() >= deadline) {
15144
15692
  return false;
@@ -15755,290 +16303,6 @@ var init_managed_session_daemon_policy = __esm({
15755
16303
  }
15756
16304
  });
15757
16305
 
15758
- // dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js
15759
- function redactExactSensitiveText(text3, sensitiveValues) {
15760
- let redacted = text3;
15761
- for (const value of sensitiveValues) {
15762
- redacted = redacted.split(value).join("[REDACTED]");
15763
- }
15764
- return redacted;
15765
- }
15766
- function redactExactSensitiveValue(value, sensitiveValues) {
15767
- if (sensitiveValues.length === 0) {
15768
- return value;
15769
- }
15770
- if (typeof value === "string") {
15771
- return redactExactSensitiveText(value, sensitiveValues);
15772
- }
15773
- if (Array.isArray(value)) {
15774
- const entries = value;
15775
- return entries.map((item) => redactExactSensitiveValue(item, sensitiveValues));
15776
- }
15777
- if (!isRecord(value)) {
15778
- return value;
15779
- }
15780
- return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
15781
- key,
15782
- redactExactSensitiveValue(entryValue, sensitiveValues)
15783
- ]));
15784
- }
15785
- function redactToolDetails(details, sensitiveValues) {
15786
- const redacted = redactSensitiveValue(redactExactSensitiveValue(details, sensitiveValues));
15787
- if (!isRecord(redacted)) {
15788
- throw new Error("Browser result details must remain an object after redaction.");
15789
- }
15790
- return redacted;
15791
- }
15792
- function redactRecoveryHint(recoveryHint) {
15793
- if (!recoveryHint) {
15794
- return void 0;
15795
- }
15796
- const exampleArgs = redactInvocationArgs(recoveryHint.exampleArgs);
15797
- return {
15798
- ...recoveryHint,
15799
- exampleArgs,
15800
- exampleParams: { ...recoveryHint.exampleParams, args: exampleArgs }
15801
- };
15802
- }
15803
- function buildJsonVisibleContent(options) {
15804
- const { error, presentation, succeeded, warnings } = options;
15805
- const payload = projectAgentBrowserObservation({
15806
- ...presentation,
15807
- ...options.details,
15808
- error,
15809
- warnings: warnings !== void 0 && warnings.length > 0 ? warnings : void 0
15810
- }, succeeded);
15811
- const images = presentation.content.filter((item) => item.type === "image");
15812
- return [{ type: "text", text: JSON.stringify(payload, null, 2) }, ...images];
15813
- }
15814
- function warningLines(text3) {
15815
- return text3 === void 0 || text3.length === 0 ? void 0 : [text3];
15816
- }
15817
- function contentWithWarnings(options) {
15818
- if (options.userRequestedJson && !options.plainTextInspection) {
15819
- return buildJsonVisibleContent({
15820
- error: options.presentationEnvelope?.error,
15821
- presentation: options.presentation,
15822
- succeeded: options.succeeded,
15823
- warnings: warningLines(options.warningText)
15824
- });
15825
- }
15826
- const content = [...options.presentation.content];
15827
- if (options.warningText === void 0 || options.warningText.length === 0 || options.userRequestedJson) {
15828
- return content;
15829
- }
15830
- if (content[0]?.type === "text") {
15831
- content[0] = { ...content[0], text: `${options.warningText}
15832
-
15833
- ${content[0].text}` };
15834
- } else {
15835
- content.unshift({ type: "text", text: options.warningText });
15836
- }
15837
- return content;
15838
- }
15839
- function buildRedactedPresentationContent(options) {
15840
- return contentWithWarnings(options).map((item) => {
15841
- if (item.type !== "text") {
15842
- return item;
15843
- }
15844
- const text3 = options.userRequestedJson && !options.plainTextInspection ? JSON.stringify(redactExactSensitiveValue(JSON.parse(item.text), options.exactSensitiveValues), null, 2) : redactSensitiveText(redactExactSensitiveText(item.text, options.exactSensitiveValues));
15845
- return { type: "text", text: text3 };
15846
- });
15847
- }
15848
- function readJsonWarnings(content) {
15849
- if (content[0]?.type !== "text") {
15850
- return void 0;
15851
- }
15852
- const prior = JSON.parse(content[0].text);
15853
- if (!isRecord(prior) || !Array.isArray(prior.warnings)) {
15854
- return void 0;
15855
- }
15856
- const warnings = prior.warnings;
15857
- return warnings;
15858
- }
15859
- var init_final_result_redaction = __esm({
15860
- "dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js"() {
15861
- "use strict";
15862
- init_parsing();
15863
- init_runtime_redaction();
15864
- init_content();
15865
- }
15866
- });
15867
-
15868
- // dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js
15869
- function getElectronLaunchFailureCategory(failure) {
15870
- switch (failure.reason) {
15871
- case "aborted":
15872
- return "aborted";
15873
- case "policy-blocked":
15874
- return "policy-blocked";
15875
- case "timeout":
15876
- return "timeout";
15877
- case "non-electron-target":
15878
- return "validation-error";
15879
- case "port-not-found":
15880
- case "single-instance-conflict":
15881
- case "spawn-error":
15882
- return "upstream-error";
15883
- }
15884
- }
15885
- function pidState(pidAlive) {
15886
- if (pidAlive === void 0) {
15887
- return "state unknown";
15888
- }
15889
- return pidAlive ? "alive before cleanup" : "not alive before cleanup";
15890
- }
15891
- function formatProcessDiagnostics(diagnostics) {
15892
- const lines = [];
15893
- if (diagnostics.pid !== void 0) {
15894
- lines.push(`- PID: ${diagnostics.pid} (${pidState(diagnostics.pidAlive)}).`);
15895
- }
15896
- if (diagnostics.exitCode !== void 0 || diagnostics.exitSignal !== void 0) {
15897
- const exitParts = [
15898
- diagnostics.exitCode !== void 0 ? `code ${String(diagnostics.exitCode)}` : void 0,
15899
- diagnostics.exitSignal !== void 0 && diagnostics.exitSignal !== null && diagnostics.exitSignal.length > 0 ? `signal ${diagnostics.exitSignal}` : void 0
15900
- ].filter(Boolean).join(", ");
15901
- lines.push(`- Process exit: ${exitParts.length > 0 ? exitParts : "not observed before cleanup"}.`);
15902
- }
15903
- return lines;
15904
- }
15905
- function formatActivePort(activePort) {
15906
- const error = activePort.error !== void 0 && activePort.error.length > 0 ? ` (${activePort.error})` : "";
15907
- let state;
15908
- if (activePort.port !== void 0 && activePort.port !== 0) {
15909
- state = `found port ${activePort.port}`;
15910
- } else {
15911
- state = activePort.found ? `found but invalid${error}` : `missing${error}`;
15912
- }
15913
- return `- DevToolsActivePort: ${state} at ${activePort.path}.`;
15914
- }
15915
- function formatConnectionDiagnostics(diagnostics) {
15916
- const lines = [];
15917
- if (diagnostics.userDataDir !== void 0 && diagnostics.userDataDir.length > 0) {
15918
- lines.push(`- Wrapper profile: ${diagnostics.userDataDir}`);
15919
- }
15920
- if (diagnostics.devToolsActivePort) {
15921
- lines.push(formatActivePort(diagnostics.devToolsActivePort));
15922
- }
15923
- if (diagnostics.cdpVersionReached === false) {
15924
- lines.push("- CDP /json/version: did not return a valid payload before timeout.");
15925
- }
15926
- if (diagnostics.timeoutMs !== void 0 || diagnostics.elapsedMs !== void 0) {
15927
- lines.push(`- Timing: ${diagnostics.elapsedMs ?? "unknown"}ms elapsed${diagnostics.timeoutMs !== void 0 ? ` of ${diagnostics.timeoutMs}ms timeout` : ""}.`);
15928
- }
15929
- if (!diagnostics.outputCaptured) {
15930
- lines.push("- App stdout/stderr: not captured by this wrapper launch path.");
15931
- }
15932
- return lines;
15933
- }
15934
- function formatElectronLaunchFailureDiagnostics(failure) {
15935
- const diagnostics = failure?.diagnostics;
15936
- if (!diagnostics) {
15937
- return void 0;
15938
- }
15939
- const lines = [
15940
- "Electron launch diagnostics:",
15941
- ...formatProcessDiagnostics(diagnostics),
15942
- ...formatConnectionDiagnostics(diagnostics)
15943
- ];
15944
- if (failure.reason !== "aborted") {
15945
- lines.push("Retry guidance: increase electron.timeoutMs, try targetType:'any', pass an explicit appPath/executablePath, quit any already-running singleton instance, then retry launch.");
15946
- }
15947
- return lines.join("\n");
15948
- }
15949
- function buildElectronHostFailureResult(options) {
15950
- const text3 = [
15951
- options.errorText,
15952
- formatElectronLaunchFailureDiagnostics(options.launchFailure),
15953
- options.launchFailure?.cleanupError !== void 0 && options.launchFailure.cleanupError.length > 0 ? `Electron launch cleanup warning: ${options.launchFailure.cleanupError}` : void 0
15954
- ].filter((item) => item !== void 0 && item.length > 0).join("\n");
15955
- const details = {
15956
- args: [],
15957
- compiledElectron: options.compiledElectron,
15958
- electron: {
15959
- action: options.compiledElectron.action,
15960
- error: options.errorText,
15961
- failure: options.launchFailure,
15962
- status: options.status ?? "failed"
15963
- },
15964
- managedSessionOutcome: options.managedSessionOutcome,
15965
- ...buildAgentBrowserResultCategoryDetails({
15966
- args: [],
15967
- errorText: options.errorText,
15968
- failureCategory: options.failureCategory,
15969
- succeeded: false,
15970
- timedOut: options.failureCategory === "timeout"
15971
- }),
15972
- summary: options.errorText
15973
- };
15974
- return {
15975
- content: [{ type: "text", text: redactSensitiveText(text3) }],
15976
- details: redactToolDetails(details, []),
15977
- isError: true
15978
- };
15979
- }
15980
- function formatElectronTargetLines(targets, limit = 8) {
15981
- const shownTargets = targets.slice(0, limit);
15982
- const lines = shownTargets.map((target) => {
15983
- const typeTitle = [target.type, target.title].filter(Boolean).join(" ");
15984
- const fallback = target.id === void 0 || target.id.length === 0 ? "target" : target.id;
15985
- const label = typeTitle.length > 0 ? typeTitle : fallback;
15986
- return `- ${label}${target.url !== void 0 && target.url.length > 0 ? ` \u2014 ${target.url}` : ""}`;
15987
- });
15988
- if (targets.length > shownTargets.length) {
15989
- lines.push(`- ... ${targets.length - shownTargets.length} more target(s) omitted`);
15990
- }
15991
- return lines;
15992
- }
15993
- function formatSnapshotHandoff(handoff) {
15994
- if (handoff.refSnapshot && handoff.refSnapshot.refIds.length > 0) {
15995
- const retries = handoff.snapshotRetryCount;
15996
- return `Snapshot handoff: ${handoff.refSnapshot.refIds.length} interactive ref(s)${retries !== void 0 && retries !== 0 ? ` after ${retries} retry attempt(s)` : ""}.`;
15997
- }
15998
- return "Snapshot handoff: no interactive refs returned after a short readiness retry; run snapshot -i once more before assuming the Electron UI is unusable.";
15999
- }
16000
- function formatHandoffText(handoff) {
16001
- switch (handoff?.handoff) {
16002
- case "snapshot":
16003
- return formatSnapshotHandoff(handoff);
16004
- case "tabs":
16005
- return "Tabs handoff completed: safer diagnostic starting point; no interactive refs were captured.";
16006
- case "connect":
16007
- return "Connect handoff completed: run snapshot -i before using interactive refs.";
16008
- case void 0:
16009
- return void 0;
16010
- }
16011
- }
16012
- function formatElectronLaunchText(options) {
16013
- const lines = [
16014
- `Electron launch: ${options.record.appName} attached as ${options.record.sessionName ?? "managed session"} (launchId ${options.record.launchId}, port ${options.record.port}).`,
16015
- `Identifiers: launchId ${options.record.launchId} for electron.status/electron.cleanup/electron.probe; sessionName ${options.record.sessionName ?? "not attached"} for browser snapshot/tab commands.`,
16016
- "Profile note: electron.launch starts an isolated temporary profile; it does not reuse the app's normal signed-in profile or attach to an already-running authenticated app.",
16017
- "For already-authenticated desktop app content, do not stop here: if host tools are allowed and the app is not running, launch the normal app with --remote-debugging-port=<port>, verify the port, then run agent_browser connect <port>; if it is already running without a debug port, ask before relaunching it.",
16018
- ...formatElectronTargetLines(options.targets)
16019
- ];
16020
- const handoffText = formatHandoffText(options.handoff);
16021
- if (handoffText !== void 0) {
16022
- lines.push(handoffText);
16023
- }
16024
- lines.push(`Cleanup: use details.nextActions cleanup-electron-launch or call electron.cleanup with launchId ${options.record.launchId} when finished.`);
16025
- if (options.handoff?.error !== void 0 && options.handoff.error.length > 0) {
16026
- lines.push(`Handoff warning: ${options.handoff.error}`);
16027
- }
16028
- if (options.upstreamText.trim().length > 0) {
16029
- lines.push("", options.upstreamText.trim());
16030
- }
16031
- return lines.join("\n");
16032
- }
16033
- var init_final_result_electron = __esm({
16034
- "dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js"() {
16035
- "use strict";
16036
- init_categories();
16037
- init_runtime_redaction();
16038
- init_final_result_redaction();
16039
- }
16040
- });
16041
-
16042
16306
  // dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js
16043
16307
  function isLaunchIdentity(value) {
16044
16308
  return value.version === 1 && value.launchedByWrapper === true && typeof value.launchId === "string" && typeof value.appName === "string" && typeof value.executablePath === "string" && typeof value.userDataDir === "string" && typeof value.port === "number" && typeof value.createdAtMs === "number";
@@ -16053,6 +16317,7 @@ function hasValidOptionalFields(value) {
16053
16317
  "packageSource",
16054
16318
  "platform",
16055
16319
  "sessionName",
16320
+ "startIdentity",
16056
16321
  "webSocketDebuggerUrl"
16057
16322
  ];
16058
16323
  return strings.every((field) => value[field] === void 0 || typeof value[field] === "string") && ["pid", "processGroupId"].every((field) => value[field] === void 0 || typeof value[field] === "number");
@@ -16128,25 +16393,25 @@ var init_branch = __esm({
16128
16393
 
16129
16394
  // dist/extensions/agent-browser/lib/electron/discovery-evidence.js
16130
16395
  import { constants as fsConstants } from "node:fs";
16131
- import { access as access2, readdir as readdir7, realpath as realpath2, stat as stat10 } from "node:fs/promises";
16396
+ import { access as access2, readdir as readdir7, realpath as realpath2, stat as stat9 } from "node:fs/promises";
16132
16397
  import { basename as basename6, dirname as dirname12, extname as extname4, join as join21 } from "node:path";
16133
16398
  async function isDirectory(path) {
16134
16399
  try {
16135
- return (await stat10(path)).isDirectory();
16400
+ return (await stat9(path)).isDirectory();
16136
16401
  } catch {
16137
16402
  return false;
16138
16403
  }
16139
16404
  }
16140
16405
  async function isFile(path) {
16141
16406
  try {
16142
- return (await stat10(path)).isFile();
16407
+ return (await stat9(path)).isFile();
16143
16408
  } catch {
16144
16409
  return false;
16145
16410
  }
16146
16411
  }
16147
16412
  async function isExecutableFile(path) {
16148
16413
  try {
16149
- if (!(await stat10(path)).isFile()) {
16414
+ if (!(await stat9(path)).isFile()) {
16150
16415
  return false;
16151
16416
  }
16152
16417
  await access2(path, fsConstants.X_OK);
@@ -16171,7 +16436,7 @@ async function directoryContainsChromePak(directory) {
16171
16436
  }
16172
16437
  }
16173
16438
  async function hasElectronAppPayload(resourcesDirectory) {
16174
- return await pathExists(join21(resourcesDirectory, "app.asar")) || await isDirectory(join21(resourcesDirectory, "app"));
16439
+ return await pathExists(join21(resourcesDirectory, "app.asar")) || await pathExists(join21(resourcesDirectory, "default_app.asar")) || await isDirectory(join21(resourcesDirectory, "app"));
16175
16440
  }
16176
16441
  async function hasLinuxElectronEvidence(executablePath) {
16177
16442
  const resolved = await resolveRealPath(executablePath);
@@ -18936,7 +19201,7 @@ var init_final_result_actions = __esm({
18936
19201
  });
18937
19202
 
18938
19203
  // dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js
18939
- import { stat as stat11 } from "node:fs/promises";
19204
+ import { stat as stat10 } from "node:fs/promises";
18940
19205
  import { isAbsolute as isAbsolute8, resolve as resolve11 } from "node:path";
18941
19206
  import { setTimeout as sleepMs } from "node:timers/promises";
18942
19207
  function getTimeoutProgressSteps(options) {
@@ -18971,7 +19236,7 @@ function getTimeoutStepArtifactPath(commandTokens) {
18971
19236
  async function statTimeoutArtifactPath(absolutePath) {
18972
19237
  for (let attempt = 0; attempt < 3; attempt += 1) {
18973
19238
  try {
18974
- const stats = await stat11(absolutePath);
19239
+ const stats = await stat10(absolutePath);
18975
19240
  return { exists: true, sizeBytes: stats.size };
18976
19241
  } catch {
18977
19242
  if (attempt < 2) {
@@ -19180,12 +19445,12 @@ var init_timeout_diagnostics = __esm({
19180
19445
 
19181
19446
  // dist/extensions/agent-browser/lib/executable-path.js
19182
19447
  import { constants as fsConstants2 } from "node:fs";
19183
- import { access as access3, stat as stat12 } from "node:fs/promises";
19448
+ import { access as access3, stat as stat11 } from "node:fs/promises";
19184
19449
  import { delimiter, join as join26 } from "node:path";
19185
19450
  async function isExecutableFile2(candidate) {
19186
19451
  try {
19187
19452
  await access3(candidate, fsConstants2.X_OK);
19188
- return (await stat12(candidate)).isFile();
19453
+ return (await stat11(candidate)).isFile();
19189
19454
  } catch {
19190
19455
  return false;
19191
19456
  }
@@ -19208,8 +19473,8 @@ var init_executable_path = __esm({
19208
19473
 
19209
19474
  // dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js
19210
19475
  import { setTimeout as sleepMs2 } from "node:timers/promises";
19211
- function boundedSessionResult(data, field, limit) {
19212
- return boundElectronProbeString(extractStringResultField2(data, "result") ?? extractStringResultField2(data, field), limit);
19476
+ function sessionResult(data, field) {
19477
+ return extractStringResultField2(data, "result") ?? extractStringResultField2(data, field);
19213
19478
  }
19214
19479
  async function collectManagedSessionCommandData(options) {
19215
19480
  try {
@@ -19220,7 +19485,7 @@ async function collectManagedSessionCommandData(options) {
19220
19485
  }
19221
19486
  async function collectElectronManagedSessionUrl(options) {
19222
19487
  const urlResult = await collectManagedSessionCommandData({ ...options, args: ["get", "url"] });
19223
- const url = boundElectronProbeString(extractStringResultField2(urlResult.data, "result") ?? extractStringResultField2(urlResult.data, "url"), 300);
19488
+ const url = sessionResult(urlResult.data, "url");
19224
19489
  return urlResult.error !== void 0 && urlResult.error !== "" ? { error: urlResult.error } : { url };
19225
19490
  }
19226
19491
  async function collectElectronManagedSessionTarget(options) {
@@ -19229,8 +19494,8 @@ async function collectElectronManagedSessionTarget(options) {
19229
19494
  }
19230
19495
  const request = { ...options, sessionName: options.sessionName };
19231
19496
  const urlResult = await collectManagedSessionCommandData({ ...request, args: ["get", "url"] });
19232
- const url = boundedSessionResult(urlResult.data, "url", 300);
19233
- if ((urlResult.error ?? "") !== "" || url === void 0 || url === "") {
19497
+ const url = sessionResult(urlResult.data, "url");
19498
+ if ((urlResult.error ?? "") !== "" || url === void 0 || url.trim() === "") {
19234
19499
  return {
19235
19500
  error: urlResult.error ?? "get url returned no active page URL.",
19236
19501
  sessionName: options.sessionName
@@ -19240,7 +19505,7 @@ async function collectElectronManagedSessionTarget(options) {
19240
19505
  ...request,
19241
19506
  args: ["get", "title"]
19242
19507
  });
19243
- const title = boundedSessionResult(titleResult.data, "title", 160);
19508
+ const title = boundElectronProbeString(sessionResult(titleResult.data, "title"), 160);
19244
19509
  return {
19245
19510
  sessionName: options.sessionName,
19246
19511
  title,
@@ -19260,12 +19525,13 @@ async function collectQaAttachedTarget(options) {
19260
19525
  url: target.url
19261
19526
  };
19262
19527
  }
19263
- return collectElectronManagedSessionTarget({
19528
+ const observed = await collectElectronManagedSessionTarget({
19264
19529
  cwd: options.cwd,
19265
19530
  namespace: options.namespace,
19266
19531
  sessionName: options.sessionName,
19267
19532
  signal: options.signal
19268
19533
  });
19534
+ return observed ? presentElectronManagedSessionTarget(observed) : void 0;
19269
19535
  }
19270
19536
  function formatQaAttachedTargetText(target) {
19271
19537
  return target ? ["QA attached target:", target.sessionName, target.title, target.url].filter((part) => typeof part === "string" && part.length > 0).join(" \u2014 ") : void 0;
@@ -19394,11 +19660,12 @@ var init_electron_observation = __esm({
19394
19660
  init_session_page_state();
19395
19661
  init_session_state();
19396
19662
  init_diagnostic_values();
19663
+ init_final_result_electron();
19397
19664
  }
19398
19665
  });
19399
19666
 
19400
19667
  // dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js
19401
- import { stat as stat13 } from "node:fs/promises";
19668
+ import { stat as stat12 } from "node:fs/promises";
19402
19669
  import { setTimeout as sleepMs3 } from "node:timers/promises";
19403
19670
  import { isAbsolute as isAbsolute9, resolve as resolve12 } from "node:path";
19404
19671
  function comparePriorNavigationUrl(priorUrl, url) {
@@ -19541,7 +19808,7 @@ async function collectExistingExplicitArtifactPaths(entries, cwd) {
19541
19808
  }
19542
19809
  const absolutePath = entry.absolutePath ?? (isAbsolute9(entry.path) ? entry.path : resolve12(cwd, entry.path));
19543
19810
  try {
19544
- await stat13(absolutePath);
19811
+ await stat12(absolutePath);
19545
19812
  } catch {
19546
19813
  continue;
19547
19814
  }
@@ -20312,6 +20579,7 @@ function statusNextActions(options) {
20312
20579
  }
20313
20580
  function buildElectronStatusResult(options) {
20314
20581
  const nextActions = statusNextActions(options);
20582
+ const managedSessions = options.managedSessions.map(presentElectronManagedSessionTarget);
20315
20583
  const soleRecord = options.records.length === 1 ? options.records[0] : void 0;
20316
20584
  const details = {
20317
20585
  args: [],
@@ -20321,8 +20589,8 @@ function buildElectronStatusResult(options) {
20321
20589
  identifierList: options.records.length > 1 ? options.records.map(buildElectronIdentifiers) : void 0,
20322
20590
  identifiers: soleRecord ? buildElectronIdentifiers(soleRecord) : void 0,
20323
20591
  launches: options.records,
20324
- managedSession: options.managedSessions.length === 1 ? options.managedSessions[0] : void 0,
20325
- managedSessions: options.managedSessions.length > 0 ? options.managedSessions : void 0,
20592
+ managedSession: managedSessions.length === 1 ? managedSessions[0] : void 0,
20593
+ managedSessions: managedSessions.length > 0 ? managedSessions : void 0,
20326
20594
  sessionMismatch: options.mismatches.length === 1 ? options.mismatches[0] : void 0,
20327
20595
  sessionMismatches: options.mismatches.length > 1 ? options.mismatches : void 0,
20328
20596
  status: "succeeded",
@@ -20405,6 +20673,7 @@ var init_status = __esm({
20405
20673
  init_session_state();
20406
20674
  init_branch();
20407
20675
  init_policy();
20676
+ init_final_result_electron();
20408
20677
  }
20409
20678
  });
20410
20679
 
@@ -20459,7 +20728,7 @@ function extractElectronProbeTabs(data) {
20459
20728
  tabId: getTrimmedString(tab.tabId) ?? getTrimmedString(tab.id),
20460
20729
  title: getTrimmedString(tab.title) ?? getTrimmedString(tab.label),
20461
20730
  type: getTrimmedString(tab.type),
20462
- url: getTrimmedString(tab.url)
20731
+ url: typeof tab.url === "string" ? tab.url : void 0
20463
20732
  }));
20464
20733
  if (allTabs.length === 0) {
20465
20734
  return {};
@@ -20521,7 +20790,7 @@ function summarizeElectronProbeSnapshot(data) {
20521
20790
  function getElectronProbeSummary(probe) {
20522
20791
  const parts = [
20523
20792
  probe.title !== void 0 && probe.title.length > 0 ? `title "${probe.title}"` : void 0,
20524
- probe.url !== void 0 && probe.url.length > 0 ? `url ${probe.url}` : void 0,
20793
+ probe.url !== void 0 && probe.url.length > 0 ? `url ${boundElectronProbeString(probe.url, 300) ?? ""}` : void 0,
20525
20794
  probe.focusedElement ? "focused element" : void 0,
20526
20795
  probe.tabs ? `${probe.tabs.total} tab(s)` : void 0,
20527
20796
  probe.snapshot ? `${probe.snapshot.refCount} ref(s)` : void 0
@@ -20588,17 +20857,14 @@ async function runElectronProbeCommandData(options) {
20588
20857
  function probeCommandError(result, label) {
20589
20858
  return result.error !== void 0 && result.error.length > 0 ? `${label}: ${result.error}` : void 0;
20590
20859
  }
20591
- function probeString(data, field, limit) {
20592
- return boundElectronProbeString(extractStringResultField2(data, "result") ?? extractStringResultField2(data, field), limit);
20593
- }
20594
20860
  async function collectElectronProbe(options) {
20595
20861
  const urlResult = await runElectronProbeCommandData({ ...options, args: ["get", "url"] });
20596
20862
  const urlError = probeCommandError(urlResult, "get url");
20597
20863
  if (urlError !== void 0) {
20598
20864
  throw new Error(urlError);
20599
20865
  }
20600
- const url = probeString(urlResult.data, "url", 300);
20601
- if (url === void 0 || url.length === 0) {
20866
+ const url = extractStringResultField2(urlResult.data, "result") ?? extractStringResultField2(urlResult.data, "url");
20867
+ if (url === void 0 || url.trim().length === 0) {
20602
20868
  throw new Error("get url returned no active page URL.");
20603
20869
  }
20604
20870
  const titleResult = await runElectronProbeCommandData({ ...options, args: ["get", "title"] });
@@ -20629,7 +20895,7 @@ async function collectElectronProbe(options) {
20629
20895
  snapshot,
20630
20896
  status: errors.length === 0 ? "succeeded" : "partial",
20631
20897
  tabs,
20632
- title: probeString(titleResult.data, "title", 160),
20898
+ title: boundElectronProbeString(extractStringResultField2(titleResult.data, "result") ?? extractStringResultField2(titleResult.data, "title"), 160),
20633
20899
  url
20634
20900
  };
20635
20901
  return { ...probe, summary: getElectronProbeSummary(probe) };
@@ -20645,6 +20911,17 @@ var init_probe_collection = __esm({
20645
20911
  });
20646
20912
 
20647
20913
  // dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js
20914
+ function presentProbeTab(tab) {
20915
+ return { ...tab, url: boundElectronProbeString(tab.url) };
20916
+ }
20917
+ function presentProbe(probe) {
20918
+ return {
20919
+ ...probe,
20920
+ activeTab: probe.activeTab ? presentProbeTab(probe.activeTab) : void 0,
20921
+ tabs: probe.tabs ? { ...probe.tabs, shown: probe.tabs.shown.map(presentProbeTab) } : void 0,
20922
+ url: boundElectronProbeString(probe.url, 300)
20923
+ };
20924
+ }
20648
20925
  function presentStrings(values) {
20649
20926
  return values.filter((value) => value !== void 0 && value.length > 0);
20650
20927
  }
@@ -20757,7 +21034,8 @@ function probeNextActions(options) {
20757
21034
  return options.mismatch ? appendUniqueAgentBrowserNextActions([...mismatch], base) : appendUniqueAgentBrowserNextActions([...base], mismatch);
20758
21035
  }
20759
21036
  function buildElectronProbeResult(options) {
20760
- const { refSnapshot: _refSnapshot, ...boundedProbe } = options.probe;
21037
+ const probe = presentProbe(options.probe);
21038
+ const { refSnapshot: _refSnapshot, ...boundedProbe } = probe;
20761
21039
  const nextActions = probeNextActions(options);
20762
21040
  const details = {
20763
21041
  args: [],
@@ -20784,7 +21062,12 @@ function buildElectronProbeResult(options) {
20784
21062
  usedImplicitSession: options.probeContext.mode === "current-managed-session"
20785
21063
  };
20786
21064
  return {
20787
- content: [{ type: "text", text: redactSensitiveText(formatElectronProbeVisibleText(options)) }],
21065
+ content: [
21066
+ {
21067
+ type: "text",
21068
+ text: redactSensitiveText(formatElectronProbeVisibleText({ ...options, probe }))
21069
+ }
21070
+ ],
20788
21071
  details: redactToolDetails(details, []),
20789
21072
  isError: false
20790
21073
  };
@@ -20792,6 +21075,7 @@ function buildElectronProbeResult(options) {
20792
21075
  var init_probe_presentation = __esm({
20793
21076
  "dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js"() {
20794
21077
  "use strict";
21078
+ init_cdp();
20795
21079
  init_action_recommendations();
20796
21080
  init_categories();
20797
21081
  init_next_actions();
@@ -20967,253 +21251,6 @@ var init_probe = __esm({
20967
21251
  }
20968
21252
  });
20969
21253
 
20970
- // dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js
20971
- function storageTextContainsSecret(text3) {
20972
- if (STORAGE_TOKEN_VALUE_PATTERN.test(text3) || STORAGE_SECRET_VALUE_WORD_PATTERN.test(text3) || STORAGE_EMAIL_VALUE_PATTERN.test(text3) || STORAGE_IDENTITY_VALUE_PATTERN.test(text3)) {
20973
- return true;
20974
- }
20975
- if (storageTextIsSensitiveUrl(text3) || redactSensitiveText(text3) !== text3) {
20976
- return true;
20977
- }
20978
- try {
20979
- const parsed = JSON.parse(text3);
20980
- return valueContainsStorageSecret(parsed);
20981
- } catch {
20982
- return false;
20983
- }
20984
- }
20985
- function storageTextIsSensitiveUrl(text3) {
20986
- try {
20987
- const url = new URL(text3);
20988
- return url.protocol === "http:" || url.protocol === "https:" || url.username.length > 0 || url.password.length > 0 || url.search.length > 0;
20989
- } catch {
20990
- return false;
20991
- }
20992
- }
20993
- function valueContainsStorageSecret(value) {
20994
- if (typeof value === "string") {
20995
- const trimmed = value.trim();
20996
- return trimmed.length > 0 && storageTextContainsSecret(trimmed);
20997
- }
20998
- if (Array.isArray(value)) {
20999
- return value.some((item) => valueContainsStorageSecret(item));
21000
- }
21001
- if (!isRecord(value)) {
21002
- return false;
21003
- }
21004
- return Object.entries(value).some(([key, entryValue]) => STORAGE_SECRET_KEY_PATTERN.test(key) || valueContainsStorageSecret(entryValue));
21005
- }
21006
- function shouldRevealStorageValue(key, value) {
21007
- if (key === void 0 || key.length === 0 || STORAGE_SECRET_KEY_PATTERN.test(key) || !STORAGE_BENIGN_KEY_PATTERN.test(key)) {
21008
- return false;
21009
- }
21010
- if (valueContainsStorageSecret(value)) {
21011
- return false;
21012
- }
21013
- if (typeof value === "string") {
21014
- return value.length <= STORAGE_VALUE_PREVIEW_MAX_CHARS;
21015
- }
21016
- return value === null || typeof value === "number" || typeof value === "boolean";
21017
- }
21018
- function formatStorageValue(key, value) {
21019
- if (!shouldRevealStorageValue(key, value)) {
21020
- return "[REDACTED]";
21021
- }
21022
- return typeof value === "string" ? redactModelFacingText(value) : stringifyModelFacing(value);
21023
- }
21024
- function storageRedactionReason(key) {
21025
- return key !== void 0 && key.length > 0 && STORAGE_SECRET_KEY_PATTERN.test(key) ? "sensitive-key" : "sensitive-value";
21026
- }
21027
- function redactStorageEntryValue(item) {
21028
- const key = getStringField(item, "key") ?? getStringField(item, "name");
21029
- if (!Object.hasOwn(item, "value") || shouldRevealStorageValue(key, item.value)) {
21030
- return redactSensitiveValue(item);
21031
- }
21032
- const redacted = redactSensitiveValue({ ...item, value: void 0 });
21033
- if (!isRecord(redacted)) {
21034
- throw new Error("Storage record redaction did not return a record");
21035
- }
21036
- return {
21037
- ...redacted,
21038
- value: "[REDACTED]",
21039
- valueRedacted: true,
21040
- valueRedactionReason: storageRedactionReason(key)
21041
- };
21042
- }
21043
- function redactStorageField(owner, key, value) {
21044
- if (key === "data" && isRecord(value)) {
21045
- return Object.fromEntries(Object.entries(value).map(([storageKey, storageValue]) => [
21046
- storageKey,
21047
- shouldRevealStorageValue(storageKey, storageValue) ? redactSensitiveValue(storageValue) : "[REDACTED]"
21048
- ]));
21049
- }
21050
- if ((key === "entries" || key === "items") && Array.isArray(value)) {
21051
- return value.map((item) => isRecord(item) ? redactStorageEntryValue(item) : redactSensitiveValue(item));
21052
- }
21053
- if (key === "value") {
21054
- const itemKey = getStringField(owner, "key") ?? getStringField(owner, "name");
21055
- return shouldRevealStorageValue(itemKey, value) ? redactSensitiveValue(value) : "[REDACTED]";
21056
- }
21057
- return redactSensitiveValue(value);
21058
- }
21059
- function redactStorageData(value) {
21060
- if (Array.isArray(value)) {
21061
- return value.map((item) => redactStorageData(item));
21062
- }
21063
- if (!isRecord(value)) {
21064
- return redactSensitiveValue(value);
21065
- }
21066
- const entries = Object.fromEntries(Object.entries(value).map(([key2, entryValue]) => [
21067
- key2,
21068
- redactStorageField(value, key2, entryValue)
21069
- ]));
21070
- const key = getStringField(value, "key") ?? getStringField(value, "name");
21071
- if (Object.hasOwn(value, "value") && !shouldRevealStorageValue(key, value.value)) {
21072
- entries.valueRedacted = true;
21073
- entries.valueRedactionReason = storageRedactionReason(key);
21074
- }
21075
- return entries;
21076
- }
21077
- function formatStorageEntry(item, index) {
21078
- if (!isRecord(item)) {
21079
- return `${index + 1}. [REDACTED]`;
21080
- }
21081
- const rawKey = getStringField(item, "key") ?? getStringField(item, "name") ?? `(entry ${index + 1})`;
21082
- const key = redactModelFacingText(rawKey);
21083
- return Object.hasOwn(item, "value") ? `${key}: ${formatStorageValue(rawKey, item.value)}` : key;
21084
- }
21085
- function formatStorageMutationText(data, type) {
21086
- const key = getStringField(data, "key");
21087
- if (key !== void 0 && Object.hasOwn(data, "value")) {
21088
- return `${type} ${redactModelFacingText(key)}: ${formatStorageValue(key, data.value)}`;
21089
- }
21090
- if (key !== void 0 && data.set === true) {
21091
- return `${type} set: ${redactModelFacingText(key)}`;
21092
- }
21093
- return data.cleared === true || data.clear === true ? `${type} cleared.` : void 0;
21094
- }
21095
- function formatStorageText(data) {
21096
- const type = getStringField(data, "type") ?? getStringField(data, "storage") ?? "storage";
21097
- if (isRecord(data.data)) {
21098
- const text3 = Object.entries(data.data).map(([key, value]) => `${redactModelFacingText(key)}: ${formatStorageValue(key, value)}`).join("\n");
21099
- return text3.length > 0 ? text3 : `${type}: no entries.`;
21100
- }
21101
- const entries = getArrayField(data, "entries") ?? getArrayField(data, "items");
21102
- if (entries) {
21103
- return entries.length === 0 ? `${type}: no entries.` : entries.map(formatStorageEntry).join("\n");
21104
- }
21105
- return formatStorageMutationText(data, type);
21106
- }
21107
- function formatCookieRecordText(item, fallbackName) {
21108
- const name = redactModelFacingText(getStringField(item, "name") ?? fallbackName);
21109
- const domain = getStringField(item, "domain");
21110
- const path = getStringField(item, "path");
21111
- const flags = [
21112
- item.httpOnly === true ? "httpOnly" : void 0,
21113
- item.secure === true ? "secure" : void 0
21114
- ].filter(Boolean).join(", ");
21115
- const location = [domain, path].filter(Boolean).join("");
21116
- return [
21117
- name,
21118
- location.length > 0 ? `(${redactModelFacingText(location)})` : void 0,
21119
- flags.length > 0 ? `[${flags}]` : void 0
21120
- ].filter(Boolean).join(" ");
21121
- }
21122
- function formatCookiesText(data) {
21123
- const cookies = getArrayField(data, "cookies");
21124
- if (cookies) {
21125
- return cookies.length === 0 ? "No cookies." : cookies.map((item, index) => isRecord(item) ? formatCookieRecordText(item, `(cookie ${index + 1})`) : `${index + 1}. [REDACTED]`).join("\n");
21126
- }
21127
- if (getStringField(data, "name") !== void 0 || getStringField(data, "domain") !== void 0 || getStringField(data, "path") !== void 0 || Object.hasOwn(data, "value")) {
21128
- return formatCookieRecordText(data, "cookie");
21129
- }
21130
- if (data.set === true) {
21131
- return "Cookie set.";
21132
- }
21133
- return data.cleared === true || data.clear === true ? "Cookies cleared." : void 0;
21134
- }
21135
- var STORAGE_VALUE_PREVIEW_MAX_CHARS, STORAGE_SECRET_KEY_PATTERN, STORAGE_BENIGN_KEY_PATTERN, STORAGE_TOKEN_VALUE_PATTERN, STORAGE_SECRET_VALUE_WORD_PATTERN, STORAGE_EMAIL_VALUE_PATTERN, STORAGE_IDENTITY_VALUE_PATTERN;
21136
- var init_diagnostic_storage = __esm({
21137
- "dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js"() {
21138
- "use strict";
21139
- init_parsing();
21140
- init_runtime();
21141
- init_common();
21142
- STORAGE_VALUE_PREVIEW_MAX_CHARS = 160;
21143
- STORAGE_SECRET_KEY_PATTERN = /(?:access(?:_|-)?token|account|api(?:_|-)?key|auth(?:orization)?|bearer|client(?:_|-)?secret|cookie|credential|csrf|email|id(?:_|-)?token|jwt|pass(?:word)?|private(?:_|-)?key|profile|refresh(?:_|-)?token|secret|session|sid|sig(?:nature)?|token|user(?:name)?|x(?:_|-)?api(?:_|-)?key|xsrf)/i;
21144
- STORAGE_BENIGN_KEY_PATTERN = /^(?:color(?:scheme)?|debug|dev|experiment|feature(?:flag)?|flag|language|layout|locale|mode|onboarding|sort|tab|theme|timezone|tour|variant|view)$/i;
21145
- STORAGE_TOKEN_VALUE_PATTERN = /(?:\bBearer\s+[A-Za-z0-9._~-]+|\bBasic\s+[A-Za-z0-9+/=]+|^[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$|(?=.*[A-Za-z])(?=.*\d)[A-Za-z0-9_~+/=-]{32,})/;
21146
- STORAGE_SECRET_VALUE_WORD_PATTERN = /(?:secret|token|password|passwd|bearer|credential|authorization|cookie|session[-_ ]?id)/i;
21147
- STORAGE_EMAIL_VALUE_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
21148
- STORAGE_IDENTITY_VALUE_PATTERN = /(?:^|[\s:=/_-])(?:account|profile|session|sid|user(?:id|name)?)(?:[\s:=/_-]|$)/i;
21149
- }
21150
- });
21151
-
21152
- // dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js
21153
- function redactStatefulValues(value) {
21154
- if (Array.isArray(value)) {
21155
- return value.map((item) => redactStatefulValues(item));
21156
- }
21157
- if (!isRecord(value)) {
21158
- return redactSensitiveValue(value);
21159
- }
21160
- return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => [
21161
- key,
21162
- key.toLowerCase() === "value" ? "[REDACTED]" : redactStatefulValues(entryValue)
21163
- ]));
21164
- }
21165
- function storageTextKey(command) {
21166
- const operation = command.commandTokens?.[2];
21167
- if (operation === "get") {
21168
- return command.commandTokens?.[3];
21169
- }
21170
- return operation === "set" || operation === "clear" ? void 0 : operation;
21171
- }
21172
- function redactStorageText(command, text3) {
21173
- const key = storageTextKey(command);
21174
- if (key !== void 0 && text3.startsWith(`${key}: `)) {
21175
- const suffix = text3.endsWith("\n") ? "\n" : "";
21176
- const value = text3.slice(key.length + 2, suffix.length > 0 ? -1 : void 0);
21177
- return `${key}: ${formatStorageValue(key, value)}${suffix}`;
21178
- }
21179
- return text3.replace(/^([^\r\n]*?): ([^\r\n]*)/gm, (_line, entryKey, value) => `${entryKey}: ${formatStorageValue(entryKey, value)}`);
21180
- }
21181
- function redactNativeContextText(command, text3, stdin) {
21182
- if (command.command === "batch") {
21183
- const steps = getUpstreamEffectiveBatchSteps(command.commandTokens ?? ["batch"], stdin);
21184
- const cookieRedacted = steps.some((step) => step[0] === "cookies") ? redactNativeContextText({ command: "cookies" }, text3) : text3;
21185
- return steps.some((step) => step[0] === "storage") ? redactNativeContextText({ command: "storage" }, cookieRedacted) : cookieRedacted;
21186
- }
21187
- if (command.command === "cookies") {
21188
- return text3.replace(/^([^=\r\n]*)=([^\r\n]*)/gm, "$1=[REDACTED]");
21189
- }
21190
- return command.command === "storage" ? redactStorageText(command, text3) : text3;
21191
- }
21192
- function redactPresentationData(command, data, stdin) {
21193
- if (typeof data === "string") {
21194
- return redactSensitiveText(redactNativeContextText(command, data, stdin));
21195
- }
21196
- if (command.command === "cookies") {
21197
- return redactStatefulValues(data);
21198
- }
21199
- if (command.command === "storage") {
21200
- return redactStorageData(data);
21201
- }
21202
- if (command.command === "state" && command.subcommand === "show") {
21203
- return redactStatefulValues(data);
21204
- }
21205
- return redactSensitiveValue(data);
21206
- }
21207
- var init_diagnostic_redaction = __esm({
21208
- "dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js"() {
21209
- "use strict";
21210
- init_parsing();
21211
- init_batch_stdin();
21212
- init_runtime();
21213
- init_diagnostic_storage();
21214
- }
21215
- });
21216
-
21217
21254
  // dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js
21218
21255
  function getScreenshotCapture(command) {
21219
21256
  if (command[0] !== "screenshot") {
@@ -22904,11 +22941,11 @@ var init_batch_step = __esm({
22904
22941
  });
22905
22942
 
22906
22943
  // dist/extensions/agent-browser/lib/results/presentation/batch-recording.js
22907
- import { stat as stat16 } from "node:fs/promises";
22944
+ import { stat as stat15 } from "node:fs/promises";
22908
22945
  async function unverifiedRecordingArtifact(artifact, subcommand) {
22909
22946
  const { recordingState: _recordingState, willExistOnStop: _willExistOnStop, ...terminal } = artifact;
22910
22947
  try {
22911
- const file = await stat16(artifact.absolutePath);
22948
+ const file = await stat15(artifact.absolutePath);
22912
22949
  return {
22913
22950
  ...terminal,
22914
22951
  exists: file.isFile(),
@@ -24712,6 +24749,7 @@ var init_skills = __esm({
24712
24749
  SkillShellWords = class {
24713
24750
  words = [];
24714
24751
  current = "";
24752
+ wordStarted = false;
24715
24753
  quote;
24716
24754
  index = 0;
24717
24755
  input;
@@ -24719,9 +24757,10 @@ var init_skills = __esm({
24719
24757
  this.input = input;
24720
24758
  }
24721
24759
  flush() {
24722
- if (this.current.length > 0) {
24760
+ if (this.wordStarted) {
24723
24761
  this.words.push(this.current);
24724
24762
  this.current = "";
24763
+ this.wordStarted = false;
24725
24764
  }
24726
24765
  }
24727
24766
  appendEscape() {
@@ -24744,14 +24783,17 @@ var init_skills = __esm({
24744
24783
  }
24745
24784
  consumeUnquoted(char) {
24746
24785
  if (char === "'" || char === '"') {
24786
+ this.wordStarted = true;
24747
24787
  this.quote = char === "'" ? "single" : "double";
24748
24788
  } else if (char === "\\") {
24789
+ this.wordStarted = true;
24749
24790
  this.appendEscape();
24750
- } else if (char === "#" && this.current.length === 0) {
24791
+ } else if (char === "#" && !this.wordStarted) {
24751
24792
  return false;
24752
24793
  } else if (/\s/.test(char)) {
24753
24794
  this.flush();
24754
24795
  } else {
24796
+ this.wordStarted = true;
24755
24797
  this.current += char;
24756
24798
  }
24757
24799
  return true;
@@ -26048,7 +26090,7 @@ function launchFailureMessage(reason, target, detail) {
26048
26090
  case "aborted":
26049
26091
  return `Electron launch was aborted${target ? ` before ${label} finished starting` : " before the app started"}.`;
26050
26092
  case "non-electron-target":
26051
- return `Electron launch rejected: ${label} does not have Electron framework evidence.`;
26093
+ return `Electron launch rejected: ${label} does not have the required Electron runtime and app payload evidence.`;
26052
26094
  case "policy-blocked":
26053
26095
  return detail ?? `Electron launch blocked by caller policy for ${label}.`;
26054
26096
  case "single-instance-conflict":
@@ -26138,6 +26180,7 @@ var init_launch = __esm({
26138
26180
  init_discovery();
26139
26181
  init_temp();
26140
26182
  init_text();
26183
+ init_process_identity();
26141
26184
  init_launch_monitor();
26142
26185
  init_launch_process();
26143
26186
  init_launch_types();
@@ -26154,6 +26197,7 @@ var init_launch = __esm({
26154
26197
  timeoutMs;
26155
26198
  deadlineMs;
26156
26199
  appArgs;
26200
+ startIdentity;
26157
26201
  constructor(options, target, userDataDir, timing) {
26158
26202
  this.options = options;
26159
26203
  this.target = target;
@@ -26228,6 +26272,7 @@ var init_launch = __esm({
26228
26272
  platform: this.target.platform,
26229
26273
  port,
26230
26274
  processGroupId: process.platform === "win32" ? void 0 : pid,
26275
+ startIdentity: this.startIdentity,
26231
26276
  targetType: this.options.targetType,
26232
26277
  userDataDir: this.userDataDir,
26233
26278
  version: ELECTRON_LAUNCH_RECORD_VERSION,
@@ -26245,6 +26290,11 @@ var init_launch = __esm({
26245
26290
  if (this.process.child === void 0) {
26246
26291
  return this.fail(isElectronLaunchAborted(this.options.signal) ? "aborted" : "spawn-error", this.process.spawnError?.message);
26247
26292
  }
26293
+ const pid = this.process.child.pid;
26294
+ this.startIdentity = pid === void 0 ? void 0 : await readProcessStartIdentity(pid, process.platform, {
26295
+ deadline: this.deadlineMs,
26296
+ signal: this.options.signal
26297
+ });
26248
26298
  const portResult = await pollDevToolsActivePort({
26249
26299
  deadlineMs: this.deadlineMs,
26250
26300
  getChildExit: this.process.childExit,
@@ -28020,6 +28070,13 @@ async function collectSnapshotEvidence(options, request) {
28020
28070
  const fullSnapshot = extractRefSnapshotFromData(snapshotData);
28021
28071
  const diff = request.diff ? buildSnapshotDiff(options.previousRefSnapshot, fullSnapshot) : void 0;
28022
28072
  if (fullSnapshot) {
28073
+ if (fullSnapshot.target) {
28074
+ options.sessionPageState.applyTabTarget({
28075
+ sessionName: options.sessionStateKey ?? options.sessionName,
28076
+ target: fullSnapshot.target,
28077
+ update: options.sessionPageStateUpdate
28078
+ });
28079
+ }
28023
28080
  options.sessionPageState.applyRefSnapshot({
28024
28081
  sessionName: options.sessionStateKey ?? options.sessionName,
28025
28082
  snapshot: fullSnapshot,
@@ -28092,6 +28149,7 @@ function snapshotToolResult(options, request, evidence, presentation) {
28092
28149
  fullOutputPaths: presentation.fullOutputPaths,
28093
28150
  refSnapshot: evidence.fullSnapshot,
28094
28151
  sessionMode: options.sessionMode,
28152
+ sessionTabTarget: options.sessionPageState.get(options.sessionStateKey ?? options.sessionName).tabTarget,
28095
28153
  snapshotDiff: evidence.diff,
28096
28154
  snapshotFilter: snapshotFilterDetails(request, evidence),
28097
28155
  snapshotViewport: evidence.viewport,
@@ -28332,7 +28390,7 @@ var init_network_page_filter = __esm({
28332
28390
 
28333
28391
  // dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js
28334
28392
  function getContainerScrollRequest(commandTokens) {
28335
- if (commandTokens[0] !== "scroll" || commandTokens.length < 3) {
28393
+ if (commandTokens[0] !== "scroll" || commandTokens.length < 3 || commandTokens.length > 4) {
28336
28394
  return void 0;
28337
28395
  }
28338
28396
  const selector = commandTokens[1];
@@ -28456,7 +28514,7 @@ function getPageScrollToRequest(commandTokens) {
28456
28514
  return void 0;
28457
28515
  }
28458
28516
  if (commandTokens[1]?.toLowerCase() === "to") {
28459
- return getPageScrollTarget(commandTokens.at(2));
28517
+ return commandTokens.length === 3 ? getPageScrollTarget(commandTokens.at(2)) : void 0;
28460
28518
  }
28461
28519
  const direction = commandTokens[1]?.toLowerCase();
28462
28520
  if (!isPageScrollDirection(direction) || commandTokens.length > 3) {
@@ -33164,7 +33222,7 @@ var KeyedAsyncExecutionQueue = class {
33164
33222
  async run(key, namespace, work, signal) {
33165
33223
  const entry = this.entries.get(key) ?? { queue: new AsyncExecutionQueue(), users: 0 };
33166
33224
  if (entry.queue.isCurrent()) {
33167
- return work();
33225
+ return entry.queue.run(work, signal);
33168
33226
  }
33169
33227
  const barrier = this.barriers.get(getAgentBrowserSessionIdentityKey("", namespace)) ?? Promise.resolve();
33170
33228
  entry.users += 1;
@@ -34331,133 +34389,133 @@ function StringEnum(values, options) {
34331
34389
  init_discovery_types();
34332
34390
  init_types();
34333
34391
  var AGENT_BROWSER_ADVANCED_TOOLS = ["action", "qa", "electron", "source", "network"];
34334
- function outputProperties(Type) {
34392
+ function outputProperties() {
34335
34393
  return {
34336
- outputPath: Type.Optional(Type.String({
34394
+ outputPath: JsonSchema.Optional(JsonSchema.String({
34337
34395
  description: "Result-data path, separate from browser artifact paths.",
34338
34396
  minLength: 1
34339
34397
  })),
34340
- timeoutMs: Type.Optional(Type.Integer({ description: "Timeout in ms; exceed explicit waits.", minimum: 1 }))
34398
+ timeoutMs: JsonSchema.Optional(JsonSchema.Integer({ description: "Timeout in ms; exceed explicit waits.", minimum: 1 }))
34341
34399
  };
34342
34400
  }
34343
- function sessionModeProperty(Type, StringEnum2) {
34344
- return Type.Optional(StringEnum2(["auto", "fresh"], {
34401
+ function sessionModeProperty() {
34402
+ return JsonSchema.Optional(StringEnum(["auto", "fresh"], {
34345
34403
  description: "Native configured sessions win; auto reuses the browser, fresh intentionally launches a separate managed browser.",
34346
34404
  default: DEFAULT_SESSION_MODE
34347
34405
  }));
34348
34406
  }
34349
- function createAgentBrowserParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34350
- return Type.Unsafe(Type.Object({
34351
- args: Type.Array(Type.String(), {
34407
+ function createAgentBrowserParamsSchema() {
34408
+ return JsonSchema.Unsafe(JsonSchema.Object({
34409
+ args: JsonSchema.Array(JsonSchema.String(), {
34352
34410
  description: "Native agent-browser argv without the binary or shell syntax. Fixed sequences: batch --bail with JSON-array stdin.",
34353
34411
  minItems: 1
34354
34412
  }),
34355
- stdin: Type.Optional(Type.String({
34413
+ stdin: JsonSchema.Optional(JsonSchema.String({
34356
34414
  description: "Native batch JSON, eval --stdin source, or auth save --password-stdin text."
34357
34415
  })),
34358
- ...outputProperties(Type),
34359
- sessionMode: sessionModeProperty(Type, StringEnum2)
34416
+ ...outputProperties(),
34417
+ sessionMode: sessionModeProperty()
34360
34418
  }, { additionalProperties: false }));
34361
34419
  }
34362
- function createAgentBrowserCodeParamsSchema(Type = JsonSchema) {
34363
- return Type.Unsafe(Type.Object({
34364
- code: Type.String({
34420
+ function createAgentBrowserCodeParamsSchema() {
34421
+ return JsonSchema.Unsafe(JsonSchema.Object({
34422
+ code: JsonSchema.String({
34365
34423
  description: "JavaScript with await browser({args, stdin?, timeoutMs?}), emit(JSON), and emitImage(image handle). Fresh JS context; persistent browser.",
34366
34424
  minLength: 1,
34367
34425
  maxLength: 65536
34368
34426
  }),
34369
- session: Type.Optional(Type.String({
34427
+ session: JsonSchema.Optional(JsonSchema.String({
34370
34428
  description: "Explicit native session; omitted uses the ordinary default browser.",
34371
34429
  minLength: 1
34372
34430
  })),
34373
- namespace: Type.Optional(Type.String({
34431
+ namespace: JsonSchema.Optional(JsonSchema.String({
34374
34432
  description: "Native namespace; empty string selects the default namespace."
34375
34433
  })),
34376
- ...outputProperties(Type),
34377
- timeoutMs: Type.Optional(Type.Integer({ minimum: 1, maximum: AGENT_BROWSER_CODE_MAX_TIMEOUT_MS }))
34434
+ ...outputProperties(),
34435
+ timeoutMs: JsonSchema.Optional(JsonSchema.Integer({ minimum: 1, maximum: AGENT_BROWSER_CODE_MAX_TIMEOUT_MS }))
34378
34436
  }, { additionalProperties: false }));
34379
34437
  }
34380
- function createAgentBrowserActionParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34381
- return Type.Unsafe(Type.Object({
34382
- action: StringEnum2(AGENT_BROWSER_SEMANTIC_ACTIONS),
34383
- locator: Type.Optional(StringEnum2(AGENT_BROWSER_SEMANTIC_LOCATORS, {
34438
+ function createAgentBrowserActionParamsSchema() {
34439
+ return JsonSchema.Unsafe(JsonSchema.Object({
34440
+ action: StringEnum(AGENT_BROWSER_SEMANTIC_ACTIONS),
34441
+ locator: JsonSchema.Optional(StringEnum(AGENT_BROWSER_SEMANTIC_LOCATORS, {
34384
34442
  description: "Select supports role or label."
34385
34443
  })),
34386
- value: Type.Optional(Type.String({
34444
+ value: JsonSchema.Optional(JsonSchema.String({
34387
34445
  description: "Locator value or select option; label text for select by label."
34388
34446
  })),
34389
- values: Type.Optional(Type.Array(Type.String(), {
34447
+ values: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String(), {
34390
34448
  description: "Select options; required for select by label.",
34391
34449
  minItems: 1
34392
34450
  })),
34393
- selector: Type.Optional(Type.String({ description: "Direct selector or current @ref." })),
34394
- text: Type.Optional(Type.String({ description: "Fill text." })),
34395
- role: Type.Optional(Type.String({ description: "Role locator; select needs combobox or listbox." })),
34396
- name: Type.Optional(Type.String({ description: "Accessible name." })),
34397
- session: Type.Optional(Type.String({ description: "Upstream session name." })),
34398
- ...outputProperties(Type)
34451
+ selector: JsonSchema.Optional(JsonSchema.String({ description: "Direct selector or current @ref." })),
34452
+ text: JsonSchema.Optional(JsonSchema.String({ description: "Fill text." })),
34453
+ role: JsonSchema.Optional(JsonSchema.String({ description: "Role locator; select needs combobox or listbox." })),
34454
+ name: JsonSchema.Optional(JsonSchema.String({ description: "Accessible name." })),
34455
+ session: JsonSchema.Optional(JsonSchema.String({ description: "Upstream session name." })),
34456
+ ...outputProperties()
34399
34457
  }, {
34400
34458
  additionalProperties: false,
34401
34459
  // Top-level properties let Pi normalize optional nulls before validating branches.
34402
34460
  anyOf: [
34403
- Type.Object({
34404
- action: StringEnum2(["select"]),
34405
- locator: Type.Optional(StringEnum2(["role", "label"]))
34461
+ JsonSchema.Object({
34462
+ action: StringEnum(["select"]),
34463
+ locator: JsonSchema.Optional(StringEnum(["role", "label"]))
34406
34464
  }, { not: { required: ["text"] } }),
34407
- Type.Object({ action: StringEnum2(["check", "click", "fill"]) }, { not: { required: ["values"] } })
34465
+ JsonSchema.Object({ action: StringEnum(["check", "click", "fill"]) }, { not: { required: ["values"] } })
34408
34466
  ]
34409
34467
  }));
34410
34468
  }
34411
- function createAgentBrowserQaParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34412
- return Type.Unsafe(Type.Object({
34413
- url: Type.Optional(Type.String()),
34414
- attached: Type.Optional(Type.Boolean()),
34415
- expectedText: Type.Optional(Type.Union([Type.String(), Type.Array(Type.String())])),
34416
- expectedSelector: Type.Optional(Type.String()),
34417
- screenshotPath: Type.Optional(Type.String()),
34418
- checkConsole: Type.Optional(Type.Boolean()),
34419
- checkErrors: Type.Optional(Type.Boolean()),
34420
- checkNetwork: Type.Optional(Type.Boolean()),
34421
- loadState: Type.Optional(StringEnum2(AGENT_BROWSER_QA_LOAD_STATES)),
34422
- ...outputProperties(Type),
34423
- sessionMode: sessionModeProperty(Type, StringEnum2)
34469
+ function createAgentBrowserQaParamsSchema() {
34470
+ return JsonSchema.Unsafe(JsonSchema.Object({
34471
+ url: JsonSchema.Optional(JsonSchema.String()),
34472
+ attached: JsonSchema.Optional(JsonSchema.Boolean()),
34473
+ expectedText: JsonSchema.Optional(JsonSchema.Union([JsonSchema.String(), JsonSchema.Array(JsonSchema.String())])),
34474
+ expectedSelector: JsonSchema.Optional(JsonSchema.String()),
34475
+ screenshotPath: JsonSchema.Optional(JsonSchema.String()),
34476
+ checkConsole: JsonSchema.Optional(JsonSchema.Boolean()),
34477
+ checkErrors: JsonSchema.Optional(JsonSchema.Boolean()),
34478
+ checkNetwork: JsonSchema.Optional(JsonSchema.Boolean()),
34479
+ loadState: JsonSchema.Optional(StringEnum(AGENT_BROWSER_QA_LOAD_STATES)),
34480
+ ...outputProperties(),
34481
+ sessionMode: sessionModeProperty()
34424
34482
  }, {
34425
34483
  additionalProperties: false,
34426
34484
  anyOf: [
34427
- Type.Object({
34428
- attached: Type.Literal(true),
34429
- sessionMode: Type.Optional(StringEnum2(["auto"]))
34485
+ JsonSchema.Object({
34486
+ attached: JsonSchema.Literal(true),
34487
+ sessionMode: JsonSchema.Optional(StringEnum(["auto"]))
34430
34488
  }, { not: { required: ["url"] } }),
34431
- Type.Object({ url: Type.String(), attached: Type.Optional(Type.Literal(false)) })
34489
+ JsonSchema.Object({ url: JsonSchema.String(), attached: JsonSchema.Optional(JsonSchema.Literal(false)) })
34432
34490
  ]
34433
34491
  }));
34434
34492
  }
34435
- function createAgentBrowserElectronParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34436
- const common = { outputPath: outputProperties(Type).outputPath };
34437
- const timeoutMs = Type.Optional(Type.Integer({ minimum: 1 }));
34493
+ function createAgentBrowserElectronParamsSchema() {
34494
+ const common = { outputPath: outputProperties().outputPath };
34495
+ const timeoutMs = JsonSchema.Optional(JsonSchema.Integer({ minimum: 1 }));
34438
34496
  const list = {
34439
- query: Type.Optional(Type.String({ description: "Case-insensitive app filter.", minLength: 1 })),
34440
- maxResults: Type.Optional(Type.Integer({
34497
+ query: JsonSchema.Optional(JsonSchema.String({ description: "Case-insensitive app filter.", minLength: 1 })),
34498
+ maxResults: JsonSchema.Optional(JsonSchema.Integer({
34441
34499
  description: `Result cap; default ${ELECTRON_DISCOVERY_DEFAULT_MAX_RESULTS}, clamped to ${ELECTRON_DISCOVERY_MAX_RESULTS}.`,
34442
34500
  minimum: 1
34443
34501
  }))
34444
34502
  };
34445
34503
  const launch = {
34446
- appPath: Type.Optional(Type.String({ description: "macOS .app path.", minLength: 1 })),
34447
- appName: Type.Optional(Type.String({ description: "Name from agent_browser_electron list.", minLength: 1 })),
34448
- bundleId: Type.Optional(Type.String({ minLength: 1 })),
34449
- executablePath: Type.Optional(Type.String({ minLength: 1 })),
34450
- appArgs: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
34451
- handoff: Type.Optional(StringEnum2(AGENT_BROWSER_ELECTRON_HANDOFFS)),
34452
- targetType: Type.Optional(StringEnum2(AGENT_BROWSER_ELECTRON_TARGET_TYPES)),
34504
+ appPath: JsonSchema.Optional(JsonSchema.String({ description: "macOS .app path.", minLength: 1 })),
34505
+ appName: JsonSchema.Optional(JsonSchema.String({ description: "Name from agent_browser_electron list.", minLength: 1 })),
34506
+ bundleId: JsonSchema.Optional(JsonSchema.String({ minLength: 1 })),
34507
+ executablePath: JsonSchema.Optional(JsonSchema.String({ minLength: 1 })),
34508
+ appArgs: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 }))),
34509
+ handoff: JsonSchema.Optional(StringEnum(AGENT_BROWSER_ELECTRON_HANDOFFS)),
34510
+ targetType: JsonSchema.Optional(StringEnum(AGENT_BROWSER_ELECTRON_TARGET_TYPES)),
34453
34511
  timeoutMs,
34454
- allow: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
34455
- deny: Type.Optional(Type.Array(Type.String({ minLength: 1 })))
34512
+ allow: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 }))),
34513
+ deny: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 })))
34456
34514
  };
34457
- const probe = { launchId: Type.Optional(Type.String({ minLength: 1 })), timeoutMs };
34458
- const lifecycle = { ...probe, all: Type.Optional(Type.Literal(true)) };
34459
- return Type.Unsafe(Type.Object({
34460
- action: StringEnum2(["list", "launch", "status", "cleanup", "probe"]),
34515
+ const probe = { launchId: JsonSchema.Optional(JsonSchema.String({ minLength: 1 })), timeoutMs };
34516
+ const lifecycle = { ...probe, all: JsonSchema.Optional(JsonSchema.Literal(true)) };
34517
+ return JsonSchema.Unsafe(JsonSchema.Object({
34518
+ action: StringEnum(["list", "launch", "status", "cleanup", "probe"]),
34461
34519
  ...list,
34462
34520
  ...launch,
34463
34521
  ...lifecycle,
@@ -34465,47 +34523,47 @@ function createAgentBrowserElectronParamsSchema(Type = JsonSchema, StringEnum2 =
34465
34523
  }, {
34466
34524
  additionalProperties: false,
34467
34525
  anyOf: [
34468
- Type.Object({ action: StringEnum2(["list"]), ...list, ...common }, { additionalProperties: false }),
34469
- Type.Object({ action: StringEnum2(["launch"]), ...launch, ...common }, { additionalProperties: false }),
34470
- Type.Object({ action: StringEnum2(["status", "cleanup"]), ...lifecycle, ...common }, { additionalProperties: false, not: { required: ["launchId", "all"] } }),
34471
- Type.Object({ action: StringEnum2(["probe"]), ...probe, ...common }, { additionalProperties: false })
34526
+ JsonSchema.Object({ action: StringEnum(["list"]), ...list, ...common }, { additionalProperties: false }),
34527
+ JsonSchema.Object({ action: StringEnum(["launch"]), ...launch, ...common }, { additionalProperties: false }),
34528
+ JsonSchema.Object({ action: StringEnum(["status", "cleanup"]), ...lifecycle, ...common }, { additionalProperties: false, not: { required: ["launchId", "all"] } }),
34529
+ JsonSchema.Object({ action: StringEnum(["probe"]), ...probe, ...common }, { additionalProperties: false })
34472
34530
  ]
34473
34531
  }));
34474
34532
  }
34475
- function createAgentBrowserSourceParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34476
- return Type.Unsafe(Type.Object({
34477
- selector: Type.Optional(Type.String({ description: "Visible selector or @ref." })),
34478
- reactFiberId: Type.Optional(Type.String({ description: "React fiber id; requires --enable react-devtools." })),
34479
- componentName: Type.Optional(Type.String({ description: "Component for local source search." })),
34480
- includeDomHints: Type.Optional(Type.Boolean({ description: "Inspect DOM hints; default true." })),
34481
- maxWorkspaceFiles: Type.Optional(Type.Integer({
34533
+ function createAgentBrowserSourceParamsSchema() {
34534
+ return JsonSchema.Unsafe(JsonSchema.Object({
34535
+ selector: JsonSchema.Optional(JsonSchema.String({ description: "Visible selector or @ref." })),
34536
+ reactFiberId: JsonSchema.Optional(JsonSchema.String({ description: "React fiber id; requires --enable react-devtools." })),
34537
+ componentName: JsonSchema.Optional(JsonSchema.String({ description: "Component for local source search." })),
34538
+ includeDomHints: JsonSchema.Optional(JsonSchema.Boolean({ description: "Inspect DOM hints; default true." })),
34539
+ maxWorkspaceFiles: JsonSchema.Optional(JsonSchema.Integer({
34482
34540
  description: "Source scan cap; default 2000.",
34483
34541
  minimum: 1,
34484
34542
  maximum: SOURCE_LOOKUP_MAX_WORKSPACE_FILES
34485
34543
  })),
34486
- ...outputProperties(Type),
34487
- sessionMode: sessionModeProperty(Type, StringEnum2)
34544
+ ...outputProperties(),
34545
+ sessionMode: sessionModeProperty()
34488
34546
  }, { additionalProperties: false }));
34489
34547
  }
34490
- function createAgentBrowserNetworkSourceParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34491
- return Type.Unsafe(Type.Object({
34492
- filter: Type.Optional(Type.String({ description: "Network request filter." })),
34493
- namespace: Type.Optional(Type.String()),
34494
- requestId: Type.Optional(Type.String({ description: "Request id to inspect." })),
34495
- session: Type.Optional(Type.String()),
34496
- url: Type.Optional(Type.String({ description: "Failed URL or fragment." })),
34497
- maxWorkspaceFiles: Type.Optional(Type.Integer({
34548
+ function createAgentBrowserNetworkSourceParamsSchema() {
34549
+ return JsonSchema.Unsafe(JsonSchema.Object({
34550
+ filter: JsonSchema.Optional(JsonSchema.String({ description: "Network request filter." })),
34551
+ namespace: JsonSchema.Optional(JsonSchema.String()),
34552
+ requestId: JsonSchema.Optional(JsonSchema.String({ description: "Request id to inspect." })),
34553
+ session: JsonSchema.Optional(JsonSchema.String()),
34554
+ url: JsonSchema.Optional(JsonSchema.String({ description: "Failed URL or fragment." })),
34555
+ maxWorkspaceFiles: JsonSchema.Optional(JsonSchema.Integer({
34498
34556
  description: "Source scan cap; default 2000.",
34499
34557
  minimum: 1,
34500
34558
  maximum: SOURCE_LOOKUP_MAX_WORKSPACE_FILES
34501
34559
  })),
34502
- ...outputProperties(Type),
34503
- sessionMode: sessionModeProperty(Type, StringEnum2)
34560
+ ...outputProperties(),
34561
+ sessionMode: sessionModeProperty()
34504
34562
  }, { additionalProperties: false }));
34505
34563
  }
34506
- function createAgentBrowserToolsParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
34507
- return Type.Unsafe(Type.Object({
34508
- enable: Type.Optional(Type.Array(StringEnum2(AGENT_BROWSER_ADVANCED_TOOLS), {
34564
+ function createAgentBrowserToolsParamsSchema() {
34565
+ return JsonSchema.Unsafe(JsonSchema.Object({
34566
+ enable: JsonSchema.Optional(JsonSchema.Array(StringEnum(AGENT_BROWSER_ADVANCED_TOOLS), {
34509
34567
  description: "Add capabilities to active tools; omit to list inventory."
34510
34568
  }))
34511
34569
  }, { additionalProperties: false }));
@@ -34934,15 +34992,24 @@ function validateAgentBrowserConfig(value, path, errors, warnings) {
34934
34992
  ...browser !== void 0 ? { browser } : {}
34935
34993
  };
34936
34994
  }
34937
- function parseAgentBrowserConfigLayer(raw, path, scope, errors, warnings) {
34938
- let parsed;
34995
+ function parseAgentBrowserConfigJson(raw) {
34939
34996
  try {
34940
- parsed = JSON.parse(raw);
34997
+ return { ok: true, value: JSON.parse(raw) };
34941
34998
  } catch (error) {
34942
- errors.push(`Could not parse ${scope} config ${path}: ${error instanceof Error ? error.message : describeUnknownError(error)}`);
34999
+ const location = error instanceof Error ? error.message.match(/at position \d+(?: \(line \d+ column \d+\))?/)?.[0] : void 0;
35000
+ return {
35001
+ ok: false,
35002
+ error: location === void 0 ? "Invalid JSON." : `Invalid JSON ${location}.`
35003
+ };
35004
+ }
35005
+ }
35006
+ function parseAgentBrowserConfigLayer(raw, path, scope, errors, warnings) {
35007
+ const parsed = parseAgentBrowserConfigJson(raw);
35008
+ if (!parsed.ok) {
35009
+ errors.push(`Could not parse ${scope} config ${path}: ${parsed.error}`);
34943
35010
  return;
34944
35011
  }
34945
- const config = validateAgentBrowserConfig(parsed, path, errors, warnings);
35012
+ const config = validateAgentBrowserConfig(parsed.value, path, errors, warnings);
34946
35013
  return config ? { config, path, scope } : void 0;
34947
35014
  }
34948
35015
  function describeUnknownError(value) {
@@ -35313,6 +35380,9 @@ async function resolvePreferredWebSearchCredential(state, options = {}) {
35313
35380
 
35314
35381
  // dist/extensions/agent-browser/lib/web-search.js
35315
35382
  init_runtime();
35383
+ init_parsing();
35384
+ init_content();
35385
+ init_diagnostic_redaction();
35316
35386
 
35317
35387
  // dist/extensions/agent-browser/lib/web-search-schema.js
35318
35388
  var DEFAULT_SEARCH_RESULT_COUNT = 5;
@@ -35328,67 +35398,67 @@ var EXA_SEARCH_CATEGORIES = [
35328
35398
  ];
35329
35399
  var MAX_EXA_DOMAIN_FILTERS = 20;
35330
35400
  var MAX_EXA_ADDITIONAL_QUERIES = 10;
35331
- function createExaFilterProperties(Type, StringEnum2) {
35401
+ function createExaFilterProperties() {
35332
35402
  return {
35333
- includeDomains: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
35403
+ includeDomains: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 }), {
35334
35404
  minItems: 1,
35335
35405
  maxItems: MAX_EXA_DOMAIN_FILTERS,
35336
35406
  description: `Exa only. Limit results to 1\u2013${MAX_EXA_DOMAIN_FILTERS} hostnames, path prefixes (exa.ai/docs), or wildcard subdomains (*.substack.com).`
35337
35407
  })),
35338
- excludeDomains: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
35408
+ excludeDomains: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 }), {
35339
35409
  minItems: 1,
35340
35410
  maxItems: MAX_EXA_DOMAIN_FILTERS,
35341
35411
  description: `Exa only. Exclude 1\u2013${MAX_EXA_DOMAIN_FILTERS} hostnames, path prefixes, or wildcard subdomains. Not compatible with category company or people.`
35342
35412
  })),
35343
- category: Type.Optional(StringEnum2(EXA_SEARCH_CATEGORIES, {
35413
+ category: JsonSchema.Optional(StringEnum(EXA_SEARCH_CATEGORIES, {
35344
35414
  description: "Exa-only result category. company and people cannot be combined with freshness or excludeDomains."
35345
35415
  })),
35346
- additionalQueries: Type.Optional(Type.Array(Type.String({ minLength: 1 }), {
35416
+ additionalQueries: JsonSchema.Optional(JsonSchema.Array(JsonSchema.String({ minLength: 1 }), {
35347
35417
  minItems: 1,
35348
35418
  maxItems: MAX_EXA_ADDITIONAL_QUERIES,
35349
35419
  description: `Exa only. Add 1\u2013${MAX_EXA_ADDITIONAL_QUERIES} query variations when the effective searchType is deep-lite, deep, or deep-reasoning.`
35350
35420
  })),
35351
- highlightsDynamic: Type.Optional(Type.Boolean({
35421
+ highlightsDynamic: JsonSchema.Optional(JsonSchema.Boolean({
35352
35422
  description: "Exa-only research preview. Allocate one highlight budget across all results; the wrapper sends the required Exa-Beta header. Regular per-page highlights remain the default."
35353
35423
  }))
35354
35424
  };
35355
35425
  }
35356
- function createAgentBrowserWebSearchParamsSchema(Type = JsonSchema, StringEnum2 = StringEnum) {
35357
- return Type.Object({
35358
- query: Type.String({
35426
+ function createAgentBrowserWebSearchParamsSchema() {
35427
+ return JsonSchema.Object({
35428
+ query: JsonSchema.String({
35359
35429
  minLength: 1,
35360
35430
  description: "Search query to run with the configured Exa or Brave web search provider."
35361
35431
  }),
35362
- provider: Type.Optional(StringEnum2(WEB_SEARCH_PROVIDER_PARAM_VALUES, {
35432
+ provider: JsonSchema.Optional(StringEnum(WEB_SEARCH_PROVIDER_PARAM_VALUES, {
35363
35433
  description: `Optional provider override. auto uses configured keys and preferredProvider; when both Exa and Brave are available, the default preferred provider is ${DEFAULT_WEB_SEARCH_PROVIDER}.`
35364
35434
  })),
35365
- searchType: Type.Optional(StringEnum2(EXA_SEARCH_TYPES, {
35435
+ searchType: JsonSchema.Optional(StringEnum(EXA_SEARCH_TYPES, {
35366
35436
  description: "Exa mode; omitted uses webSearch.defaultSearchType, then auto. instant (~250ms) is only for trivial lookups; fast (~450ms) favors latency; auto (~1s) is balanced. Pass searchType: deep-lite (~4s) for research before implementation unless config already defaults it; do not assume auto is deep enough. deep (4\u201315s) handles hard multi-source research; deep-reasoning (12\u201340s) is only for the hardest work. Brave ignores this field."
35367
35437
  })),
35368
- ...createExaFilterProperties(Type, StringEnum2),
35369
- count: Type.Optional(Type.Integer({
35438
+ ...createExaFilterProperties(),
35439
+ count: JsonSchema.Optional(JsonSchema.Integer({
35370
35440
  minimum: 1,
35371
35441
  maximum: MAX_SEARCH_RESULT_COUNT,
35372
35442
  description: `Number of web results to return. Defaults to ${DEFAULT_SEARCH_RESULT_COUNT}; max ${MAX_SEARCH_RESULT_COUNT}.`
35373
35443
  })),
35374
- offset: Type.Optional(Type.Integer({
35444
+ offset: JsonSchema.Optional(JsonSchema.Integer({
35375
35445
  minimum: 0,
35376
35446
  maximum: 9,
35377
35447
  description: "Zero-based result offset for pagination. Defaults to 0."
35378
35448
  })),
35379
- country: Type.Optional(Type.String({
35449
+ country: JsonSchema.Optional(JsonSchema.String({
35380
35450
  pattern: "^[A-Za-z]{2}$",
35381
35451
  description: "Optional 2-letter country code, such as US or GB."
35382
35452
  })),
35383
- searchLang: Type.Optional(Type.String({
35453
+ searchLang: JsonSchema.Optional(JsonSchema.String({
35384
35454
  minLength: 2,
35385
35455
  maxLength: 8,
35386
35456
  description: "Optional Brave search language code, such as en or en-US."
35387
35457
  })),
35388
- safesearch: Type.Optional(StringEnum2(["off", "moderate", "strict"], {
35458
+ safesearch: JsonSchema.Optional(StringEnum(["off", "moderate", "strict"], {
35389
35459
  description: "Optional search safety setting. Brave forwards this as safesearch; Exa maps moderate/strict to moderation=true."
35390
35460
  })),
35391
- freshness: Type.Optional(StringEnum2(["pd", "pw", "pm", "py"], {
35461
+ freshness: JsonSchema.Optional(StringEnum(["pd", "pw", "pm", "py"], {
35392
35462
  description: "Optional freshness window: pd=past day, pw=past week, pm=past month, py=past year."
35393
35463
  }))
35394
35464
  }, { additionalProperties: false });
@@ -35685,25 +35755,19 @@ function sleepWithAbort(ms, signal) {
35685
35755
  });
35686
35756
  }
35687
35757
  var WebSearchRequestGate = class {
35688
- now;
35689
- sleep;
35690
35758
  lastRequestStartedAt = 0;
35691
35759
  tail = Promise.resolve();
35692
- constructor(now = Date.now, sleep2 = sleepWithAbort) {
35693
- this.now = now;
35694
- this.sleep = sleep2;
35695
- }
35696
35760
  run(signal, task) {
35697
35761
  const runTask = async () => {
35698
- const elapsedMs = this.lastRequestStartedAt === 0 ? WEB_SEARCH_MIN_REQUEST_INTERVAL_MS : this.now() - this.lastRequestStartedAt;
35762
+ const elapsedMs = this.lastRequestStartedAt === 0 ? WEB_SEARCH_MIN_REQUEST_INTERVAL_MS : Date.now() - this.lastRequestStartedAt;
35699
35763
  const waitMs = Math.max(0, WEB_SEARCH_MIN_REQUEST_INTERVAL_MS - elapsedMs);
35700
35764
  if (waitMs > 0) {
35701
- await this.sleep(waitMs, signal);
35765
+ await sleepWithAbort(waitMs, signal);
35702
35766
  }
35703
35767
  if (signal?.aborted === true) {
35704
35768
  signal.throwIfAborted();
35705
35769
  }
35706
- this.lastRequestStartedAt = this.now();
35770
+ this.lastRequestStartedAt = Date.now();
35707
35771
  return task();
35708
35772
  };
35709
35773
  const result = this.tail.then(runTask, runTask);
@@ -35712,18 +35776,19 @@ var WebSearchRequestGate = class {
35712
35776
  return result;
35713
35777
  }
35714
35778
  };
35715
- function redactSearchSecret(text3, apiKey) {
35716
- return apiKey.length > 0 ? text3.split(apiKey).join("[REDACTED]") : text3;
35717
- }
35718
35779
  function formatSearchHttpError(options) {
35719
- const { provider, status, statusText, body, apiKey } = options;
35780
+ const { provider, status } = options;
35720
35781
  const providerLabel = getProviderLabel(provider);
35721
- const errorPreview = cleanSearchText(redactSearchSecret(body, apiKey), 300);
35722
35782
  if (status === 429) {
35723
- const preview = errorPreview !== void 0 ? ` Upstream details: ${redactSearchSecret(errorPreview, apiKey)}` : "";
35724
- return `${providerLabel} search rate limit exceeded (HTTP 429). Do not issue parallel or repeated agent_browser_web_search calls; use one high-signal query, inspect those results, then wait before retrying or ask the user to adjust their ${providerLabel} API plan/limits.${preview}`;
35783
+ return `${providerLabel} search rate limit exceeded (HTTP 429). Do not issue parallel or repeated agent_browser_web_search calls; use one high-signal query, inspect those results, then wait before retrying or ask the user to adjust their ${providerLabel} API plan/limits.`;
35784
+ }
35785
+ if (status === 401 || status === 403) {
35786
+ return `${providerLabel} search failed with HTTP ${status}: Check your API credential and permissions.`;
35725
35787
  }
35726
- return `${providerLabel} search failed with HTTP ${status}: ${errorPreview !== void 0 ? redactSearchSecret(errorPreview, apiKey) : statusText}`;
35788
+ if (status >= 500) {
35789
+ return `${providerLabel} search failed with HTTP ${status}: Provider unavailable; retry later.`;
35790
+ }
35791
+ return `${providerLabel} search failed with HTTP ${status}: Request rejected; check the search parameters.`;
35727
35792
  }
35728
35793
  async function fetchSearchJson(options) {
35729
35794
  if (options.signal?.aborted === true) {
@@ -35735,20 +35800,19 @@ async function fetchSearchJson(options) {
35735
35800
  options.signal?.addEventListener("abort", abort, { once: true });
35736
35801
  try {
35737
35802
  const response = await fetch(options.request, { ...options.init, signal: controller.signal });
35738
- const text3 = await response.text();
35739
35803
  if (!response.ok) {
35804
+ await response.body?.cancel().catch(() => {
35805
+ });
35740
35806
  throw new Error(formatSearchHttpError({
35741
35807
  provider: options.provider,
35742
- status: response.status,
35743
- statusText: response.statusText,
35744
- body: text3,
35745
- apiKey: options.apiKey
35808
+ status: response.status
35746
35809
  }));
35747
35810
  }
35811
+ const text3 = await response.text();
35748
35812
  try {
35749
35813
  return JSON.parse(text3);
35750
- } catch (error) {
35751
- throw new Error(`${options.invalidJsonMessage}: ${error instanceof Error ? error.message : "Unknown JSON parse failure"}`, { cause: error });
35814
+ } catch {
35815
+ throw new Error(options.invalidJsonMessage);
35752
35816
  }
35753
35817
  } finally {
35754
35818
  clearTimeout(timeout);
@@ -35827,7 +35891,6 @@ function buildExaSearchRequestBody(params, now = () => /* @__PURE__ */ new Date(
35827
35891
  }
35828
35892
  async function fetchBraveSearchJson(url, apiKey, signal) {
35829
35893
  const data = await fetchSearchJson({
35830
- apiKey,
35831
35894
  cancelMessage: "Brave search cancelled",
35832
35895
  init: { headers: { Accept: "application/json", "X-Subscription-Token": apiKey } },
35833
35896
  invalidJsonMessage: "Brave search returned invalid JSON",
@@ -35860,7 +35923,6 @@ function usesDynamicHighlights(body) {
35860
35923
  }
35861
35924
  async function fetchExaSearchJson(body, apiKey, signal, timeoutMs = SEARCH_REQUEST_TIMEOUT_MS) {
35862
35925
  const data = await fetchSearchJson({
35863
- apiKey,
35864
35926
  cancelMessage: "Exa search cancelled",
35865
35927
  init: {
35866
35928
  body: JSON.stringify(body),
@@ -35916,34 +35978,6 @@ var EXA_WEB_SEARCH_ADAPTER = {
35916
35978
  };
35917
35979
  }
35918
35980
  };
35919
- var WEB_SEARCH_PROVIDER_ADAPTERS = {
35920
- brave: {
35921
- provider: "brave",
35922
- buildRequest: BRAVE_WEB_SEARCH_ADAPTER.buildRequest,
35923
- fetchJson(request, apiKey, signal) {
35924
- if (!(request instanceof URL)) {
35925
- throw new Error("Brave search request must be a URL");
35926
- }
35927
- return BRAVE_WEB_SEARCH_ADAPTER.fetchJson(request, apiKey, signal);
35928
- },
35929
- normalizeResponse(response, params) {
35930
- return BRAVE_WEB_SEARCH_ADAPTER.normalizeResponse(parseBraveSearchResponse(response), params);
35931
- }
35932
- },
35933
- exa: {
35934
- provider: "exa",
35935
- buildRequest: EXA_WEB_SEARCH_ADAPTER.buildRequest,
35936
- fetchJson(request, apiKey, signal) {
35937
- if (!isRecord(request) || !isRecord(request.body) || typeof request.timeoutMs !== "number") {
35938
- throw new Error("Exa search request must contain a body and timeout");
35939
- }
35940
- return fetchExaSearchJson(request.body, apiKey, signal, request.timeoutMs);
35941
- },
35942
- normalizeResponse(response, params) {
35943
- return EXA_WEB_SEARCH_ADAPTER.normalizeResponse(parseExaSearchResponse(response), params);
35944
- }
35945
- }
35946
- };
35947
35981
  function prepareWebSearchRequest(provider, params, apiKey, signal) {
35948
35982
  if (provider === "exa") {
35949
35983
  const request2 = EXA_WEB_SEARCH_ADAPTER.buildRequest(params);
@@ -36041,8 +36075,12 @@ async function runWebSearch(state, params, gate, signal) {
36041
36075
  duplicatesRemoved: duplicatesRemoved > 0 ? duplicatesRemoved : void 0
36042
36076
  };
36043
36077
  }
36044
- async function presentSearchSuccess(details, params) {
36045
- const duplicateNotice = details.duplicatesRemoved !== void 0 ? `
36078
+ async function presentSearchSuccess(rawDetails, params) {
36079
+ const details = redactPresentationData({ command: "web-search" }, rawDetails);
36080
+ if (!isRecord(details) || !isWebSearchProvider(details.provider) || typeof details.returnedQuery !== "string" || !Array.isArray(details.results) || !details.results.every(isNormalizedSearchResult)) {
36081
+ throw new Error("Web search presentation has invalid result structure.");
36082
+ }
36083
+ const duplicateNotice = typeof details.duplicatesRemoved === "number" ? `
36046
36084
 
36047
36085
  Duplicate URLs removed: ${details.duplicatesRemoved}.` : "";
36048
36086
  const result = await finalizeAgentBrowserNativeResult({
@@ -36057,6 +36095,12 @@ Duplicate URLs removed: ${details.duplicatesRemoved}.` : "";
36057
36095
  const finalizedManifest = result.details.artifactManifest;
36058
36096
  return finalizedManifest === void 0 ? { ...result, details } : { ...result, details: { ...details, artifactManifest: finalizedManifest } };
36059
36097
  }
36098
+ function isNormalizedSearchResult(value) {
36099
+ if (!isRecord(value) || typeof value.title !== "string" || typeof value.url !== "string") {
36100
+ return false;
36101
+ }
36102
+ return ["description", "source", "age", "pageDate", "language"].every((field) => value[field] === void 0 || typeof value[field] === "string") && (value.highlights === void 0 || isStringArray2(value.highlights));
36103
+ }
36060
36104
  function failureCategory(error, signal) {
36061
36105
  if (signal?.aborted === true) {
36062
36106
  return "aborted";
@@ -38370,7 +38414,7 @@ async function runAgentBrowserScript(options) {
38370
38414
  }
38371
38415
 
38372
38416
  // dist/extensions/agent-browser/lib/orchestration/script-mode.js
38373
- import { stat as stat14 } from "node:fs/promises";
38417
+ import { stat as stat13 } from "node:fs/promises";
38374
38418
  import { randomUUID as randomUUID7 } from "node:crypto";
38375
38419
  init_parsing();
38376
38420
  init_browser_transcript();
@@ -38621,7 +38665,7 @@ var BrowserCodeOutput = class {
38621
38665
  if (image === void 0) {
38622
38666
  throw new Error("Browser capture returned invalid image observation geometry.");
38623
38667
  }
38624
- const file = await stat14(image.path);
38668
+ const file = await stat13(image.path);
38625
38669
  const id = `image-${this.images.size + 1}`;
38626
38670
  this.images.set(id, { observation: image, size: file.size, mtime: file.mtimeMs });
38627
38671
  return { ...image, id };
@@ -38644,7 +38688,7 @@ var BrowserCodeOutput = class {
38644
38688
  if (this.selected.size >= 8 || this.selectedBytes + image.size > 20 * 1024 * 1024) {
38645
38689
  throw new Error("Selected images exceed the code output limit (8 images / 20 MiB). Emit fewer images.");
38646
38690
  }
38647
- const file = await stat14(image.observation.path);
38691
+ const file = await stat13(image.observation.path);
38648
38692
  if (!file.isFile() || file.size !== image.size || file.mtimeMs !== image.mtime) {
38649
38693
  throw new Error("The selected image changed since capture. Capture it again before emitting it.");
38650
38694
  }
@@ -40379,7 +40423,7 @@ init_argv_grammar();
40379
40423
  init_artifact_manifest();
40380
40424
  init_runtime();
40381
40425
  init_text();
40382
- import { mkdir as mkdir5, readFile as readFile10, realpath as realpath3, stat as stat15, writeFile as writeFile3 } from "node:fs/promises";
40426
+ import { mkdir as mkdir5, readFile as readFile10, realpath as realpath3, stat as stat14, writeFile as writeFile3 } from "node:fs/promises";
40383
40427
  import { dirname as dirname15, extname as extname7, isAbsolute as isAbsolute12, resolve as resolve14 } from "node:path";
40384
40428
  function normalizeRequestedOutputPath(path) {
40385
40429
  return path.startsWith("@") ? path.slice(1) : path;
@@ -40537,7 +40581,7 @@ async function pathsReferToSameFile(left, right) {
40537
40581
  } catch {
40538
40582
  }
40539
40583
  try {
40540
- const [leftStat, rightStat] = await Promise.all([stat15(left), stat15(right)]);
40584
+ const [leftStat, rightStat] = await Promise.all([stat14(left), stat14(right)]);
40541
40585
  return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
40542
40586
  } catch {
40543
40587
  return false;