pi-agent-browser-native 0.2.77 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/CHANGELOG.md +154 -0
  2. package/README.md +69 -35
  3. package/dist/extensions/agent-browser/index.js +911 -121
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +35 -8
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +48 -7
  6. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +71 -0
  7. package/dist/extensions/agent-browser/lib/command-policy.js +1 -6
  8. package/dist/extensions/agent-browser/lib/command-taxonomy.js +35 -8
  9. package/dist/extensions/agent-browser/lib/config-policy.js +0 -5
  10. package/dist/extensions/agent-browser/lib/config.js +0 -6
  11. package/dist/extensions/agent-browser/lib/electron/cdp.js +6 -7
  12. package/dist/extensions/agent-browser/lib/electron/cleanup.js +0 -7
  13. package/dist/extensions/agent-browser/lib/electron/discovery.js +0 -7
  14. package/dist/extensions/agent-browser/lib/electron/launch.js +0 -7
  15. package/dist/extensions/agent-browser/lib/input-modes/electron.js +0 -5
  16. package/dist/extensions/agent-browser/lib/input-modes/job.js +61 -9
  17. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +2 -7
  18. package/dist/extensions/agent-browser/lib/input-modes/params.js +23 -29
  19. package/dist/extensions/agent-browser/lib/input-modes/script.js +462 -0
  20. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +51 -17
  21. package/dist/extensions/agent-browser/lib/input-modes/shared.js +0 -5
  22. package/dist/extensions/agent-browser/lib/input-modes/types.js +0 -5
  23. package/dist/extensions/agent-browser/lib/json-schema.js +0 -5
  24. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +12 -5
  25. package/dist/extensions/agent-browser/lib/managed-session-capabilities.js +0 -2
  26. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +3 -4
  27. package/dist/extensions/agent-browser/lib/managed-session-restore.js +55 -48
  28. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +2 -9
  29. package/dist/extensions/agent-browser/lib/managed-session-state-policy.js +48 -36
  30. package/dist/extensions/agent-browser/lib/managed-session-storage.js +50 -29
  31. package/dist/extensions/agent-browser/lib/navigation-policy.js +0 -5
  32. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +26 -5
  33. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +110 -30
  34. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +2 -1
  35. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +27 -26
  36. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +58 -33
  37. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +2 -1
  38. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +22 -14
  39. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/direct-anchor-download.js +1 -1
  40. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +1 -1
  41. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +1 -1
  42. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +1 -1
  43. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +148 -34
  44. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +225 -61
  45. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +74 -30
  46. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +47 -26
  47. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +40 -19
  48. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +42 -1
  49. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +299 -0
  50. package/dist/extensions/agent-browser/lib/parsing.js +0 -7
  51. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +36 -11
  52. package/dist/extensions/agent-browser/lib/playbook.js +20 -24
  53. package/dist/extensions/agent-browser/lib/process-environment.js +14 -0
  54. package/dist/extensions/agent-browser/lib/process-identity.js +4 -9
  55. package/dist/extensions/agent-browser/lib/process.js +131 -48
  56. package/dist/extensions/agent-browser/lib/prompt-policy.js +171 -27
  57. package/dist/extensions/agent-browser/lib/recording-reservations.js +183 -0
  58. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +63 -13
  59. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +68 -11
  60. package/dist/extensions/agent-browser/lib/results/categories.js +7 -9
  61. package/dist/extensions/agent-browser/lib/results/confirmation.js +0 -7
  62. package/dist/extensions/agent-browser/lib/results/contracts.js +0 -7
  63. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +0 -7
  64. package/dist/extensions/agent-browser/lib/results/envelope.js +0 -7
  65. package/dist/extensions/agent-browser/lib/results/network.js +0 -7
  66. package/dist/extensions/agent-browser/lib/results/next-actions.js +19 -35
  67. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +85 -44
  68. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +66 -11
  69. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +0 -5
  70. package/dist/extensions/agent-browser/lib/results/presentation/common.js +18 -5
  71. package/dist/extensions/agent-browser/lib/results/presentation/content.js +0 -5
  72. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +7 -6
  73. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +2 -1
  74. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +0 -5
  75. package/dist/extensions/agent-browser/lib/results/presentation/managed-list-filter.js +0 -5
  76. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +26 -16
  77. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +58 -13
  78. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +1 -15
  79. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +0 -5
  80. package/dist/extensions/agent-browser/lib/results/presentation.js +6 -8
  81. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +2 -7
  82. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +0 -7
  83. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +51 -15
  84. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +13 -14
  85. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +0 -7
  86. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +0 -7
  87. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +0 -7
  88. package/dist/extensions/agent-browser/lib/results/snapshot.js +0 -7
  89. package/dist/extensions/agent-browser/lib/results/text.js +0 -7
  90. package/dist/extensions/agent-browser/lib/runtime.js +119 -52
  91. package/dist/extensions/agent-browser/lib/session-page-state.js +62 -17
  92. package/dist/extensions/agent-browser/lib/string-enum-schema.js +0 -5
  93. package/dist/extensions/agent-browser/lib/temp.js +0 -7
  94. package/dist/extensions/agent-browser/lib/upstream-version.js +14 -0
  95. package/dist/extensions/agent-browser/lib/web-search.js +0 -5
  96. package/dist/extensions/agent-browser/script-worker.js +169 -0
  97. package/dist/scripts/agent-browser-target.mjs +3 -0
  98. package/docs/ARCHITECTURE.md +50 -31
  99. package/docs/COMMAND_REFERENCE.md +97 -41
  100. package/docs/ELECTRON.md +3 -19
  101. package/docs/RELEASE.md +8 -20
  102. package/docs/REQUIREMENTS.md +8 -6
  103. package/docs/SUPPORT_MATRIX.md +32 -25
  104. package/docs/TOOL_CONTRACT.md +107 -64
  105. package/docs/platform-smoke.md +1 -1
  106. package/package.json +7 -6
  107. package/platform-smoke.config.mjs +2 -2
  108. package/scripts/agent-browser-capability-baseline.mjs +24 -6
  109. package/scripts/agent-browser-target.mjs +3 -0
  110. package/scripts/build.mjs +41 -0
  111. package/scripts/doctor.mjs +8 -7
  112. package/scripts/platform-smoke/browser-dogfood-windows.ps1 +9 -3
  113. package/scripts/platform-smoke/targets.mjs +12 -6
  114. package/dist/extensions/agent-browser/lib/electron/text.js +0 -13
  115. package/dist/extensions/agent-browser/lib/input-modes.js +0 -10
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-artifacts.js +0 -5
  117. package/dist/extensions/agent-browser/lib/results/artifact-state.js +0 -13
  118. package/dist/extensions/agent-browser/lib/results.js +0 -14
@@ -1,21 +1,31 @@
1
- /**
2
- * Purpose: Format scalar extraction results, navigation summaries, and page-change summaries.
3
- * Responsibilities: Keep navigation/extraction presentation separate from core tool result orchestration.
4
- * Scope: Navigation and get/eval extraction formatting only.
5
- */
6
1
  import { isNavigationObservableCommandName, isPageChangeSummaryCommand } from "../../command-taxonomy.js";
7
2
  import { isRecord } from "../../parsing.js";
8
3
  import { detectConfirmationRequired } from "../confirmation.js";
9
- import { redactModelFacingText, stringifyModelFacing } from "./common.js";
4
+ import { omitUpstreamLifecycle, redactModelFacingText, stringifyModelFacing } from "./common.js";
10
5
  const NAVIGATION_SUMMARY_FIELD = "navigationSummary";
11
- function getScalarExtractionResult(data) {
12
- const { result } = data;
13
- if (typeof result === "string") {
14
- return result.trim().length > 0 ? result : undefined;
15
- }
16
- if (typeof result === "number" || typeof result === "boolean") {
6
+ const GET_RESULT_FIELDS = {
7
+ attr: "value",
8
+ count: "count",
9
+ html: "html",
10
+ text: "text",
11
+ title: "title",
12
+ url: "url",
13
+ value: "value",
14
+ };
15
+ function getScalarExtractionResult(commandInfo, data) {
16
+ const fallbackField = commandInfo.command === "get" && commandInfo.subcommand ? GET_RESULT_FIELDS[commandInfo.subcommand] ?? "" : "";
17
+ const resultField = Object.hasOwn(data, "result") ? "result" : fallbackField.length > 0 && Object.hasOwn(data, fallbackField) ? fallbackField : undefined;
18
+ if (resultField === undefined)
19
+ return undefined;
20
+ const result = data[resultField];
21
+ if (typeof result === "string")
22
+ return result.trim().length > 0 ? result : "(empty string)";
23
+ if (typeof result === "number" || typeof result === "boolean")
17
24
  return String(result);
18
- }
25
+ if (result === null || result === undefined)
26
+ return "null";
27
+ if (typeof result === "object")
28
+ return JSON.stringify(result);
19
29
  return undefined;
20
30
  }
21
31
  function getExtractionOrigin(data) {
@@ -37,7 +47,7 @@ function formatGetSummaryLabel(subcommand) {
37
47
  return `${subcommand.slice(0, 1).toUpperCase()}${subcommand.slice(1)}`;
38
48
  }
39
49
  export function formatExtractionSummary(commandInfo, data) {
40
- const scalarResult = getScalarExtractionResult(data);
50
+ const scalarResult = getScalarExtractionResult(commandInfo, data);
41
51
  if (!scalarResult) {
42
52
  return undefined;
43
53
  }
@@ -55,7 +65,7 @@ export function formatExtractionText(commandInfo, data) {
55
65
  if (commandInfo.command !== "get" && commandInfo.command !== "eval") {
56
66
  return undefined;
57
67
  }
58
- const scalarResult = getScalarExtractionResult(data);
68
+ const scalarResult = getScalarExtractionResult(commandInfo, data);
59
69
  if (!scalarResult) {
60
70
  return undefined;
61
71
  }
@@ -137,7 +147,7 @@ function stripNavigationSummary(data) {
137
147
  return rest;
138
148
  }
139
149
  export function formatNavigationActionResult(data) {
140
- const actionData = stripNavigationSummary(data);
150
+ const actionData = omitUpstreamLifecycle(stripNavigationSummary(data));
141
151
  const lines = [];
142
152
  if (typeof actionData.clicked === "string" || typeof actionData.clicked === "boolean") {
143
153
  lines.push(`Clicked: ${String(actionData.clicked)}`);
@@ -1,24 +1,54 @@
1
1
  import { isRecord } from "../../parsing.js";
2
2
  import { detectConfirmationRequired } from "../confirmation.js";
3
3
  import { formatRawSnapshotText, formatSnapshotSummary } from "../snapshot.js";
4
- import { redactModelFacingText, stringifyModelFacing } from "./common.js";
4
+ import { getPageSummary, omitUpstreamLifecycle, redactModelFacingText, stringifyModelFacing } from "./common.js";
5
5
  import { formatDiagnosticSummary, formatDiagnosticText, formatProfilesText, getStreamSummary, getTabSummary } from "./diagnostics.js";
6
6
  import { getScreenshotSummary } from "./artifacts.js";
7
7
  import { formatSkillsText } from "./skills.js";
8
8
  import { formatExtractionSummary, formatExtractionText, formatNavigationActionResult, formatNavigationSummary, getNavigationSummary, isNavigationObservableCommand, } from "./navigation.js";
9
9
  import { formatSemanticActionPresentationSummary, formatSemanticActionPresentationText, resolvePresentationCommandInfo, } from "./semantic-action.js";
10
- function getPageSummary(data) {
11
- const title = typeof data.title === "string" ? data.title : undefined;
12
- const url = typeof data.url === "string" ? data.url : undefined;
13
- if (!title && !url)
14
- return undefined;
15
- if (title && url)
16
- return `${title}\n${url}`;
17
- return title ?? url;
18
- }
19
10
  function formatConfirmationRequiredSummary(confirmation) {
20
11
  return `Confirmation required: ${confirmation.id}`;
21
12
  }
13
+ const SIMPLE_ACTION_RESULTS = {
14
+ check: { field: "checked", label: "Checked" },
15
+ click: { field: "clicked", label: "Clicked" },
16
+ fill: { field: "filled", label: "Filled" },
17
+ focus: { field: "focused", label: "Focused" },
18
+ hover: { field: "hovered", label: "Hovered" },
19
+ press: { field: "pressed", label: "Pressed" },
20
+ select: { field: "selected", label: "Selected" },
21
+ type: { field: "typed", label: "Typed" },
22
+ uncheck: { field: "unchecked", label: "Unchecked" },
23
+ };
24
+ function formatSimpleActionResult(command, data) {
25
+ if (!isRecord(data))
26
+ return undefined;
27
+ if (command === "click" && getNavigationSummary(data))
28
+ return undefined;
29
+ const definition = SIMPLE_ACTION_RESULTS[command];
30
+ if (!definition)
31
+ return undefined;
32
+ const value = data[definition.field];
33
+ if (typeof value !== "string" && typeof value !== "number" && typeof value !== "boolean")
34
+ return undefined;
35
+ return `${definition.label}: ${redactModelFacingText(String(value))}`;
36
+ }
37
+ function formatWaitResult(data) {
38
+ if (!isRecord(data))
39
+ return undefined;
40
+ if (data.waited === "timeout")
41
+ return "Fixed wait elapsed; no page condition was verified.";
42
+ for (const field of ["selector", "text", "url", "state", "waited"]) {
43
+ const value = data[field];
44
+ if (typeof value === "string" && value.length > 0)
45
+ return `Wait completed: ${redactModelFacingText(value)}`;
46
+ }
47
+ return undefined;
48
+ }
49
+ function formatCloseResult(data) {
50
+ return isRecord(data) && data.closed === true ? "Browser session closed." : undefined;
51
+ }
22
52
  const VITALS_METRICS = ["lcp", "fcp", "ttfb", "inp", "cls"];
23
53
  function coerceVitalsMetricValue(value) {
24
54
  if (typeof value === "number" && Number.isFinite(value))
@@ -80,6 +110,14 @@ function formatConfirmationRequiredText(confirmation) {
80
110
  return lines.join("\n");
81
111
  }
82
112
  const COMMAND_PRESENTERS = {
113
+ ...Object.fromEntries(Object.keys(SIMPLE_ACTION_RESULTS).map((command) => [command, {
114
+ summary: (_commandInfo, data) => formatSimpleActionResult(command, data),
115
+ text: (_commandInfo, data) => formatSimpleActionResult(command, data),
116
+ }])),
117
+ close: { summary: (_commandInfo, data) => formatCloseResult(data), text: (_commandInfo, data) => formatCloseResult(data) },
118
+ exit: { summary: (_commandInfo, data) => formatCloseResult(data), text: (_commandInfo, data) => formatCloseResult(data) },
119
+ quit: { summary: (_commandInfo, data) => formatCloseResult(data), text: (_commandInfo, data) => formatCloseResult(data) },
120
+ wait: { summary: (_commandInfo, data) => formatWaitResult(data), text: (_commandInfo, data) => formatWaitResult(data) },
83
121
  profiles: {
84
122
  summary: (_commandInfo, data) => Array.isArray(data) ? `Chrome profiles: ${data.length}` : undefined,
85
123
  text: (_commandInfo, data) => Array.isArray(data) ? formatProfilesText(data, "Chrome profiles") : undefined,
@@ -118,8 +156,12 @@ const COMMAND_PRESENTERS = {
118
156
  text: (commandInfo, data) => isRecord(data) && commandInfo.subcommand === "status" ? getStreamSummary(data) : undefined,
119
157
  },
120
158
  tab: {
121
- summary: (_commandInfo, data) => isRecord(data) && Array.isArray(data.tabs) ? `Tabs: ${data.tabs.length}` : undefined,
122
- text: (_commandInfo, data) => isRecord(data) ? getTabSummary(data) : undefined,
159
+ summary: (_commandInfo, data) => isRecord(data) && Array.isArray(data.tabs)
160
+ ? `Tabs: ${data.tabs.length}`
161
+ : isRecord(data) && data.closed === true ? "Tab closed" : undefined,
162
+ text: (_commandInfo, data) => isRecord(data) && data.closed === true
163
+ ? `Tab closed${typeof data.tabId === "string" ? `: ${redactModelFacingText(data.tabId)}` : "."}`
164
+ : isRecord(data) ? getTabSummary(data) : undefined,
123
165
  },
124
166
  vitals: {
125
167
  summary: (_commandInfo, data) => isRecord(data) ? formatVitalsSummary(data) : undefined,
@@ -216,5 +258,8 @@ export function formatPresentationContentText(commandInfo, data, compiledSemanti
216
258
  const pageSummary = getPageSummary(data);
217
259
  if (pageSummary)
218
260
  return redactModelFacingText(pageSummary);
219
- return stringifyModelFacing(data);
261
+ const { navigationSummary: _navigationSummary, ...pageData } = omitUpstreamLifecycle(data);
262
+ if (Object.keys(pageData).length > 0)
263
+ return stringifyModelFacing(pageData);
264
+ return `${presentationCommandInfo.command ?? commandInfo.command ?? "agent-browser"} completed`;
220
265
  }
@@ -1,23 +1,9 @@
1
- /**
2
- * Purpose: Map successful semanticAction results to the same presentation signals as direct ref commands.
3
- * Responsibilities: Resolve presentation command names, compact action prose, and navigation-summary probe gates.
4
- * Scope: semanticAction success presentation only.
5
- */
6
1
  import { getCompiledSemanticActionCommandIndex, isCompiledSemanticActionFindCommand, } from "../../input-modes/semantic-action.js";
7
2
  import { isRecord } from "../../parsing.js";
8
3
  import { formatNavigationSummary, getNavigationSummary, isNavigationObservableCommand, } from "./navigation.js";
9
- import { redactModelFacingText } from "./common.js";
4
+ import { getPageSummary, redactModelFacingText } from "./common.js";
10
5
  const SEMANTIC_NAVIGATION_PROBE_ACTIONS = new Set(["check", "click"]);
11
6
  const SEMANTIC_PRESENTATION_ACTIONS = new Set(["check", "click", "fill", "select"]);
12
- function getPageSummary(data) {
13
- const title = typeof data.title === "string" ? data.title : undefined;
14
- const url = typeof data.url === "string" ? data.url : undefined;
15
- if (!title && !url)
16
- return undefined;
17
- if (title && url)
18
- return `${title}\n${url}`;
19
- return title ?? url;
20
- }
21
7
  function formatSemanticActionTarget(compiled) {
22
8
  if (compiled.action === "select") {
23
9
  const selector = compiled.selector ?? "selector";
@@ -1,8 +1,3 @@
1
- /**
2
- * Purpose: Render upstream agent-browser skills output as native pi tool guidance.
3
- * Responsibilities: Format skills list/path/get results and translate agent-browser shell snippets to agent_browser tool calls.
4
- * Scope: Skills command presentation only.
5
- */
6
1
  import { isRecord } from "../../parsing.js";
7
2
  import { getStringField, redactModelFacingText, stringifyModelFacing } from "./common.js";
8
3
  function formatSkillsListText(skills) {
@@ -1,10 +1,5 @@
1
- /*
2
- * Purpose: Render parsed agent-browser results into concise pi-facing summaries, text content, and optional inline image attachments.
3
- * Responsibilities: Orchestrate specialized presentation modules, attach inline images within size limits, and keep generic record formatting distinct from envelope parsing.
4
- * Scope: Presentation shaping only; upstream stdout parsing and snapshot compaction internals live in separate modules.
5
- */
6
1
  import { isRecord } from "../parsing.js";
7
- import { extractCommandTokens } from "../runtime.js";
2
+ import { extractUpstreamCommandTokens } from "../runtime.js";
8
3
  import { buildAgentBrowserNextActions } from "./action-recommendations.js";
9
4
  import { buildAgentBrowserResultCategoryDetails } from "./categories.js";
10
5
  import { detectConfirmationRequired } from "./confirmation.js";
@@ -38,14 +33,14 @@ function shouldAddAnnotatedScreenshotGuidance(commandInfo, args) {
38
33
  }
39
34
  export async function buildToolPresentation(options) {
40
35
  const { args, artifactManifest, artifactRequest, commandInfo, compiledSemanticAction, cwd, envelope, errorText, namespace, networkRouteDiagnostics, networkRoutes, persistentArtifactStore, sessionName, } = options;
41
- const commandInfoWithTokens = commandInfo.commandTokens || !args ? commandInfo : { ...commandInfo, commandTokens: extractCommandTokens(args) };
36
+ const commandInfoWithTokens = commandInfo.commandTokens || !args ? commandInfo : { ...commandInfo, commandTokens: extractUpstreamCommandTokens(args) };
42
37
  const presentationCommandInfo = resolvePresentationCommandInfo(commandInfoWithTokens, compiledSemanticAction);
43
38
  if (errorText) {
44
39
  return buildErrorPresentation({ args, commandInfo, errorText, sessionName });
45
40
  }
46
41
  const data = enrichStreamStatusData(commandInfoWithTokens, envelope?.data);
47
42
  const presentationData = redactPresentationData(commandInfoWithTokens, data);
48
- const artifacts = await extractFileArtifacts({ artifactManifest, artifactRequest, commandInfo: presentationCommandInfo, cwd, data, sessionName });
43
+ const artifacts = await extractFileArtifacts({ artifactManifest, artifactMaxUpdatedAtMs: options.artifactMaxUpdatedAtMs, artifactMinUpdatedAtMs: options.artifactMinUpdatedAtMs, artifactRequest, commandInfo: presentationCommandInfo, cwd, data, namespace, sessionName });
49
44
  const artifactVerification = buildArtifactVerificationSummary(artifacts);
50
45
  const artifactSummary = formatArtifactSummary(artifacts);
51
46
  const summary = artifactSummary ?? formatPresentationSummary(commandInfoWithTokens, data, compiledSemanticAction);
@@ -54,6 +49,8 @@ export async function buildToolPresentation(options) {
54
49
  if (commandInfo.command === "batch" && isAgentBrowserBatchResultArray(data)) {
55
50
  presentation = await buildBatchPresentation({
56
51
  artifactManifest,
52
+ artifactMaxUpdatedAtMs: options.artifactMaxUpdatedAtMs,
53
+ artifactMinUpdatedAtMs: options.artifactMinUpdatedAtMs,
57
54
  artifactRequests: options.batchArtifactRequests,
58
55
  buildNestedToolPresentation: buildToolPresentation,
59
56
  cwd,
@@ -161,6 +158,7 @@ export async function buildToolPresentation(options) {
161
158
  failureCategory: presentationWithManifest.failureCategory,
162
159
  resultCategory: presentationWithManifest.resultCategory ?? "success",
163
160
  savedFilePath: presentationWithManifest.savedFilePath,
161
+ sessionName,
164
162
  successCategory: presentationWithManifest.successCategory,
165
163
  });
166
164
  const networkNextActions = commandInfoWithTokens.command === "network" && commandInfoWithTokens.subcommand === "requests" && presentationWithManifest.resultCategory === "success"
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Centralize recovery-oriented nextAction ids and action construction.
3
- * Responsibilities: Build tab/about:blank/no-active-page/connected-session follow-ups and rich-input recovery ids.
4
- * Scope: Recovery action contracts only; result category classification and artifact follow-ups live elsewhere.
5
- * Usage: Imported by shared result action builders and the extension entrypoint.
6
- * Invariants/Assumptions: Ids are public machine-readable contracts mirrored by docs and tests.
7
- */
8
1
  import { buildNextToolAction, withOptionalSessionArgs } from "./next-actions.js";
9
2
  export const AGENT_BROWSER_RECOVERY_NEXT_ACTION_IDS = {
10
3
  aboutBlankListTabs: "list-tabs-for-about-blank-recovery",
@@ -15,6 +8,8 @@ export const AGENT_BROWSER_RECOVERY_NEXT_ACTION_IDS = {
15
8
  selectIntendedTabAfterDrift: "select-intended-tab-after-drift",
16
9
  snapshotAfterTabRecovery: "snapshot-after-tab-recovery",
17
10
  tabDriftListTabs: "list-tabs-for-tab-drift-recovery",
11
+ tabGoneListTabs: "list-tabs-after-tab-gone",
12
+ tabGoneNewTab: "open-tab-after-tab-gone",
18
13
  };
19
14
  export const AGENT_BROWSER_RICH_INPUT_RECOVERY_NEXT_ACTION_IDS = {
20
15
  click: "click-current-editable-ref",
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Build session-aware recovery nextActions that combine result category policy with known session/tab context.
3
- * Responsibilities: Prefix recovery argv with the active session and adapt tab/about:blank/no-active/stale-ref contexts into stable nextAction lists.
4
- * Scope: Recovery nextAction assembly only; diagnostic detection and action-list merge ordering stay in the extension entrypoint.
5
- * Usage: Imported by the extension entrypoint when adding recovery nextActions to tool details.
6
- * Invariants/Assumptions: Action ids and argv ordering are public contracts; session prefixing must not double-prefix explicit --session args.
7
- */
8
1
  import { buildAgentBrowserNextActions } from "./action-recommendations.js";
9
2
  import { withOptionalSessionArgs } from "./next-actions.js";
10
3
  export function buildConnectedSessionNextActions(sessionName) {
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Own pure selector-miss recovery diagnostics for visible refs and rich editable inputs.
3
- * Responsibilities: Parse find/semantic action targets, match current snapshot refs, build public diagnostics, text, and safe nextActions.
4
- * Scope: Selector recovery policy only; subprocess snapshot probing and result orchestration stay in the extension entrypoint.
5
- * Usage: The extension entrypoint supplies command tokens plus snapshot data after a selector-not-found failure.
6
- * Invariants/Assumptions: Public fill recovery must never echo or auto-submit the user-provided fill text; guarded semanticAction fill pre-resolution may execute only one exact current editable ref.
7
- */
8
1
  import { isRecord } from "../parsing.js";
9
2
  import { extractRefSnapshotFromData } from "../session-page-state.js";
10
3
  import { getEditableRefEvidence } from "./editable-ref-evidence.js";
@@ -23,7 +16,17 @@ function isSelectorRecoveryActionName(action) {
23
16
  function getFindNameFlagValue(args, startIndex) {
24
17
  const nameFlagIndex = args.indexOf("--name", startIndex);
25
18
  const name = nameFlagIndex >= 0 ? args[nameFlagIndex + 1] : undefined;
26
- return name && !name.startsWith("-") ? name : undefined;
19
+ return typeof name === "string" && name.length > 0 ? name : undefined;
20
+ }
21
+ function collectFindTrailingValues(args, startIndex) {
22
+ const values = [];
23
+ for (let index = startIndex; index < args.length; index += 1) {
24
+ const token = args[index];
25
+ if (!token || token.startsWith("-"))
26
+ break;
27
+ values.push(token);
28
+ }
29
+ return values;
27
30
  }
28
31
  function getFindVisibleRefFallbackTarget(args, options = {}) {
29
32
  const findIndex = args[0] === "--session" ? 2 : 0;
@@ -32,8 +35,21 @@ function getFindVisibleRefFallbackTarget(args, options = {}) {
32
35
  const locator = args[findIndex + 1];
33
36
  const value = args[findIndex + 2];
34
37
  const action = args[findIndex + 3];
35
- if (!locator || !value || !isSelectorRecoveryActionName(action) || action === "select")
38
+ if (!locator || !value || !isSelectorRecoveryActionName(action))
36
39
  return undefined;
40
+ if (action === "select") {
41
+ const optionValues = collectFindTrailingValues(args, findIndex + 4);
42
+ if (locator === "role") {
43
+ if (!/^(?:combobox|listbox)$/i.test(value))
44
+ return undefined;
45
+ const targetName = getFindNameFlagValue(args, findIndex + 4);
46
+ return targetName ? { action, optionValues, roles: [value.toLowerCase()], targetName } : undefined;
47
+ }
48
+ if (locator === "label") {
49
+ return { action, optionValues, roles: ["combobox", "listbox"], targetName: value };
50
+ }
51
+ return undefined;
52
+ }
37
53
  const text = action === "fill" ? args[findIndex + 4] : undefined;
38
54
  if (action === "fill" && (!text || (!options.allowLeadingDashFillText && text.startsWith("-"))))
39
55
  return undefined;
@@ -76,7 +92,13 @@ function getVisibleRefFallbackCandidates(target, snapshotData) {
76
92
  return [];
77
93
  if (target.action === "fill" && editableEvidence === false && EDITABLE_CONTROL_ROLES.has(role.toLowerCase()))
78
94
  return [];
79
- const directRefArgs = target.action === "fill" ? undefined : [target.action, `@${ref}`];
95
+ const directRefArgs = target.action === "fill"
96
+ ? undefined
97
+ : target.action === "select" && target.optionValues && target.optionValues.length > 0
98
+ ? ["select", `@${ref}`, ...target.optionValues]
99
+ : target.action === "select"
100
+ ? undefined
101
+ : [target.action, `@${ref}`];
80
102
  return [{
81
103
  action: target.action,
82
104
  ...(directRefArgs ? { args: directRefArgs } : {}),
@@ -108,19 +130,33 @@ export function buildVisibleRefFallbackDiagnosticFromSnapshot(options) {
108
130
  }
109
131
  export function resolveVisibleRefActionFromSnapshot(options) {
110
132
  const target = getFindVisibleRefFallbackTarget(options.compiledAction.args, { allowLeadingDashFillText: true });
111
- if (!target || target.action === "select")
133
+ if (!target)
112
134
  return undefined;
113
135
  const snapshot = extractRefSnapshotFromData(options.snapshotData);
114
136
  if (!snapshot)
115
137
  return undefined;
116
- const candidates = getVisibleRefFallbackCandidates(target, options.snapshotData);
117
- if (target.action === "fill") {
118
- if (!options.allowFill || candidates.length !== 1 || target.text === undefined)
138
+ const selectOptionValues = options.compiledAction.values && options.compiledAction.values.length > 0
139
+ ? options.compiledAction.values
140
+ : target.optionValues;
141
+ const effectiveTarget = target.action === "select" && selectOptionValues
142
+ ? { ...target, optionValues: selectOptionValues }
143
+ : target;
144
+ const candidates = getVisibleRefFallbackCandidates(effectiveTarget, options.snapshotData);
145
+ if (effectiveTarget.action === "fill") {
146
+ if (!options.allowFill || candidates.length !== 1 || effectiveTarget.text === undefined)
119
147
  return undefined;
120
148
  const [candidate] = candidates;
121
149
  if (!candidate || candidate.editableEvidence === false || !EDITABLE_CONTROL_ROLES.has(candidate.role.toLowerCase()))
122
150
  return undefined;
123
- return { args: ["fill", candidate.ref, target.text], snapshot };
151
+ return { args: ["fill", candidate.ref, effectiveTarget.text], snapshot };
152
+ }
153
+ if (effectiveTarget.action === "select") {
154
+ if (candidates.length !== 1 || !selectOptionValues || selectOptionValues.length === 0)
155
+ return undefined;
156
+ const [candidate] = candidates;
157
+ if (!candidate)
158
+ return undefined;
159
+ return { args: ["select", candidate.ref, ...selectOptionValues], snapshot };
124
160
  }
125
161
  const candidate = candidates.find((item) => item.args !== undefined);
126
162
  if (!candidate?.args)
@@ -1,14 +1,9 @@
1
- /**
2
- * Purpose: Select the omitted snapshot refs most likely to be actionable controls.
3
- * Responsibilities: Classify editable, surface, primary-action, and role-based control refs with deterministic diversity and top-up rules.
4
- * Scope: High-value control ranking only; snapshot parsing, noise filtering, and presentation text live in neighboring modules.
5
- * Usage: Snapshot presentation passes already-visible, non-noise omitted refs and receives the bounded high-value subset to surface.
6
- * Invariants/Assumptions: Ranking must preserve scarce control categories before filling dominant buckets so dense desktop hosts stay navigable.
7
- */
8
1
  import { compareRefIds } from "./text.js";
9
2
  const SNAPSHOT_HIGH_VALUE_EDITABLE_REF_FILL_TARGET_LINES = 4;
10
3
  const SNAPSHOT_HIGH_VALUE_SURFACE_REF_FILL_TARGET_LINES = 3;
11
4
  const SNAPSHOT_HIGH_VALUE_PRIMARY_ACTION_REF_FILL_TARGET_LINES = 3;
5
+ const SNAPSHOT_HIGH_VALUE_NAMED_LINK_REF_FILL_TARGET_LINES = 6;
6
+ const SNAPSHOT_HIGH_VALUE_LINK_NAME_MAX_LENGTH = 80;
12
7
  const SNAPSHOT_HIGH_VALUE_CONTROL_ROLES = new Set([
13
8
  "button",
14
9
  "checkbox",
@@ -40,9 +35,6 @@ const SNAPSHOT_PRIMARY_ACTION_BUTTON_NAME_PATTERNS = [
40
35
  /^(?:add|apply|ask|attach|choose|confirm|connect|continue|create|deploy|done|download|go|insert|launch|log in|new|next|ok|open|publish|refresh|retry|run|save|search|select|send|sign in|sign up|start|submit|upload)$/i,
41
36
  /^(?:add|apply|ask|confirm|connect|continue|create|launch|new|open|refresh|retry|run|save|search|send|start|submit)\b/i,
42
37
  ];
43
- const SNAPSHOT_HIGH_VALUE_LINK_NAME_PATTERNS = [
44
- /^[a-z0-9_.-]+\/[a-z0-9_.-]+$/i,
45
- ];
46
38
  function getHighValueControlRole(entry) {
47
39
  return entry.isEditable === true && (entry.role === "unknown" || entry.role === "generic") ? "textbox" : entry.role;
48
40
  }
@@ -89,22 +81,29 @@ const SNAPSHOT_HIGH_VALUE_CONTROL_CATEGORY_RULES = [
89
81
  matches: (entry) => isPrimaryActionButtonRef(entry),
90
82
  priority: 2,
91
83
  },
84
+ {
85
+ bucketKey: () => "named-link",
86
+ fillTarget: SNAPSHOT_HIGH_VALUE_NAMED_LINK_REF_FILL_TARGET_LINES,
87
+ id: "named-link",
88
+ matches: (entry) => getHighValueControlRole(entry) === "link" && isNamedActionLinkRef(entry),
89
+ priority: 3,
90
+ },
92
91
  {
93
92
  bucketKey: (_entry, role) => role,
94
93
  id: "role",
95
94
  matches: () => true,
96
- priority: 3,
95
+ priority: 4,
97
96
  },
98
97
  ];
99
- function isHighValueLinkRef(entry) {
100
- return entry.name.length > 0 && SNAPSHOT_HIGH_VALUE_LINK_NAME_PATTERNS.some((pattern) => pattern.test(entry.name));
98
+ function isNamedActionLinkRef(entry) {
99
+ return entry.name.length > 0 && entry.name.length <= SNAPSHOT_HIGH_VALUE_LINK_NAME_MAX_LENGTH;
101
100
  }
102
101
  export function isHighValueControlEntry(entry) {
103
102
  const role = getHighValueControlRole(entry);
104
103
  if (!SNAPSHOT_HIGH_VALUE_CONTROL_ROLES.has(role))
105
104
  return false;
106
105
  if (role === "link")
107
- return isHighValueLinkRef(entry);
106
+ return isNamedActionLinkRef(entry);
108
107
  if (entry.isEditable === false && (role === "searchbox" || role === "textbox" || role === "combobox"))
109
108
  return false;
110
109
  return entry.name.length > 0 || isEditableControlRef(entry);
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Own canonical parsing and enrichment of refs from agent-browser snapshot payloads.
3
- * Responsibilities: Read structured refs, correlate them with raw snapshot lines, and infer editable/ref role evidence once for consumers.
4
- * Scope: Snapshot ref metadata only; section preview, high-value ranking, and presentation assembly live in neighboring modules.
5
- * Usage: Imported by snapshot presentation and recovery diagnostics that need consistent ref/name/role/editable evidence.
6
- * Invariants/Assumptions: Snapshot text parsing is best-effort and must tolerate upstream formatting changes by preserving structured ref data when line parsing fails.
7
- */
8
1
  import { isRecord } from "../parsing.js";
9
2
  import { getEditableRefEvidence } from "./editable-ref-evidence.js";
10
3
  import { compareRefIds, normalizeWhitespace } from "./text.js";
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Parse raw agent-browser snapshot text into previewable sections.
3
- * Responsibilities: Identify signal lines, rank content segments, build structured previews, and provide raw-outline fallback previews.
4
- * Scope: Snapshot text/section planning only; ref enrichment, high-value control ranking, spill files, and final presentation live elsewhere.
5
- * Usage: Snapshot presentation uses this module before selecting displayed refs.
6
- * Invariants/Assumptions: Parsing is best-effort and must stay resilient to upstream snapshot text format changes.
7
- */
8
1
  import { normalizeWhitespace, truncateText } from "./text.js";
9
2
  const SNAPSHOT_MAX_ADDITIONAL_SECTIONS = 2;
10
3
  const SNAPSHOT_FALLBACK_PREVIEW_MAX_LINES = 12;
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Persist full compacted snapshot payloads when model-facing output is shortened.
3
- * Responsibilities: Write persistent or secure-temp snapshot spill files and merge spill retention metadata into the session artifact manifest.
4
- * Scope: Snapshot spill artifact lifecycle only; preview planning and presentation text live in snapshot.ts and sibling modules.
5
- * Usage: Snapshot presentation calls these helpers after deciding a snapshot is too large for inline output.
6
- * Invariants/Assumptions: Explicit full-output paths are reported but not deleted here; retention state mirrors the backing storage scope.
7
- */
8
1
  import { writePersistentSessionArtifactFile, writeSecureTempFile } from "../temp.js";
9
2
  import { buildEvictedSessionArtifactEntries, formatSessionArtifactRetentionSummary, mergeSessionArtifactManifest, } from "./artifact-manifest.js";
10
3
  const SNAPSHOT_SPILL_FILE_PREFIX = "pi-agent-browser-snapshot";
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Compact large agent-browser snapshots into actionable pi-facing previews while preserving access to the raw payload when budgets allow.
3
- * Responsibilities: Parse the current raw snapshot text format, detect when structured parsing is trustworthy, derive primary/additional content sections, rank high-value refs, and fall back to raw-outline previews when the upstream snapshot text format is unfamiliar.
4
- * Scope: Snapshot-specific rendering only; generic envelope parsing, non-snapshot summaries, and image attachment live in neighboring modules.
5
- * Usage: Imported by the focused presentation module for snapshot content and summary rendering.
6
- * Invariants/Assumptions: Snapshot compaction should stay helpful even if upstream snapshot text formatting shifts, so structured parsing is best-effort and always has a resilient raw-outline fallback.
7
- */
8
1
  import { isRecord } from "../parsing.js";
9
2
  import { isHighValueControlEntry, selectHighValueControlEntries } from "./snapshot-high-value-controls.js";
10
3
  import { buildFallbackSnapshotOutline, buildRefLineOrderMap, buildSegmentPreview, buildSnapshotSegments, canUseStructuredSnapshotPreview, chooseAdditionalSegments, choosePrimarySegment, getMeaningfulSegmentLines, getSnapshotRolePriority, isChromeSectionName, isNoiseName, parseSnapshotLines, } from "./snapshot-segments.js";
@@ -1,10 +1,3 @@
1
- /**
2
- * Purpose: Hold tiny text and ref-id helpers shared by result renderers.
3
- * Responsibilities: Convert unknown values to text, count lines, normalize whitespace, truncate labels, and sort ref ids naturally.
4
- * Scope: Generic pure utilities only; no agent-browser command policy belongs here.
5
- * Usage: Imported by envelope, presentation, snapshot, and diagnostic helpers.
6
- * Invariants/Assumptions: Helpers are deterministic and side-effect free.
7
- */
8
1
  export function stringifyUnknown(value) {
9
2
  if (typeof value === "string")
10
3
  return value;