pi-agent-browser-native 0.9.3 → 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 (394) hide show
  1. package/CHANGELOG.md +106 -5
  2. package/README.md +58 -791
  3. package/dist/extensions/agent-browser/index.js +43101 -2031
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +49 -26
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +82 -93
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +129 -126
  7. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +112 -51
  8. package/dist/extensions/agent-browser/lib/browser-execution-claim-codec.js +61 -0
  9. package/dist/extensions/agent-browser/lib/browser-execution-claim-storage.js +232 -0
  10. package/dist/extensions/agent-browser/lib/browser-execution-claims.js +202 -0
  11. package/dist/extensions/agent-browser/lib/browser-execution-identity.js +77 -0
  12. package/dist/extensions/agent-browser/lib/browser-journal-branch.js +98 -0
  13. package/dist/extensions/agent-browser/lib/browser-journal-contracts.js +1 -0
  14. package/dist/extensions/agent-browser/lib/browser-journal-projection.js +221 -0
  15. package/dist/extensions/agent-browser/lib/browser-journal-reader.js +89 -0
  16. package/dist/extensions/agent-browser/lib/browser-journal-replay.js +246 -0
  17. package/dist/extensions/agent-browser/lib/browser-journal.js +103 -394
  18. package/dist/extensions/agent-browser/lib/browser-legacy-pages.js +220 -0
  19. package/dist/extensions/agent-browser/lib/browser-legacy-projection.js +282 -0
  20. package/dist/extensions/agent-browser/lib/browser-legacy-types.js +1 -0
  21. package/dist/extensions/agent-browser/lib/browser-session-conversion-stream.js +217 -0
  22. package/dist/extensions/agent-browser/lib/browser-session-conversion.js +80 -335
  23. package/dist/extensions/agent-browser/lib/browser-transcript-contracts.js +35 -0
  24. package/dist/extensions/agent-browser/lib/browser-transcript-validation.js +166 -0
  25. package/dist/extensions/agent-browser/lib/browser-transcript.js +137 -82
  26. package/dist/extensions/agent-browser/lib/browser-value-parsing.js +15 -0
  27. package/dist/extensions/agent-browser/lib/command-capabilities.js +340 -0
  28. package/dist/extensions/agent-browser/lib/command-policy.js +107 -88
  29. package/dist/extensions/agent-browser/lib/command-taxonomy.js +49 -322
  30. package/dist/extensions/agent-browser/lib/config-policy.js +138 -343
  31. package/dist/extensions/agent-browser/lib/config-providers.js +71 -0
  32. package/dist/extensions/agent-browser/lib/config-validation.js +231 -0
  33. package/dist/extensions/agent-browser/lib/config.js +20 -8
  34. package/dist/extensions/agent-browser/lib/electron/cdp.js +20 -8
  35. package/dist/extensions/agent-browser/lib/electron/cleanup.js +128 -83
  36. package/dist/extensions/agent-browser/lib/electron/discovery-darwin.js +109 -0
  37. package/dist/extensions/agent-browser/lib/electron/discovery-desktop.js +136 -0
  38. package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +90 -0
  39. package/dist/extensions/agent-browser/lib/electron/discovery-linux.js +93 -0
  40. package/dist/extensions/agent-browser/lib/electron/discovery-packages.js +162 -0
  41. package/dist/extensions/agent-browser/lib/electron/discovery-types.js +2 -0
  42. package/dist/extensions/agent-browser/lib/electron/discovery.js +140 -549
  43. package/dist/extensions/agent-browser/lib/electron/launch-monitor.js +102 -0
  44. package/dist/extensions/agent-browser/lib/electron/launch-process.js +209 -0
  45. package/dist/extensions/agent-browser/lib/electron/launch-types.js +2 -0
  46. package/dist/extensions/agent-browser/lib/electron/launch.js +261 -355
  47. package/dist/extensions/agent-browser/lib/executable-path.js +21 -12
  48. package/dist/extensions/agent-browser/lib/execution-cwd.js +35 -18
  49. package/dist/extensions/agent-browser/lib/fs-utils.js +1 -9
  50. package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
  51. package/dist/extensions/agent-browser/lib/input-modes/job.js +123 -317
  52. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +116 -0
  53. package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
  54. package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
  55. package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
  56. package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
  57. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +58 -412
  58. package/dist/extensions/agent-browser/lib/input-modes/params.js +86 -40
  59. package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
  60. package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
  61. package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
  62. package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
  63. package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
  64. package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
  65. package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
  66. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
  67. package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
  68. package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
  69. package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
  70. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
  71. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
  72. package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
  73. package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
  74. package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
  75. package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
  76. package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
  77. package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
  78. package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
  79. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
  80. package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
  81. package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
  82. package/dist/extensions/agent-browser/lib/native-output.js +43 -9
  83. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +106 -59
  84. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
  85. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
  86. package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
  87. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +164 -60
  88. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
  89. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
  90. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +203 -0
  91. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
  92. package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
  93. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
  94. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
  95. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
  96. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
  97. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
  98. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +187 -0
  99. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
  100. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
  101. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
  102. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
  103. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
  104. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
  105. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +199 -154
  106. package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
  107. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
  108. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
  109. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -205
  110. package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
  111. package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
  112. package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
  113. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
  114. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
  115. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +147 -253
  117. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
  118. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
  119. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
  120. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
  121. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
  122. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
  123. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
  124. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
  125. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
  126. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
  127. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
  128. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
  129. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
  130. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
  131. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
  132. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
  133. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
  134. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1123
  135. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
  136. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
  137. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
  138. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
  139. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
  140. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
  141. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
  142. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
  143. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
  144. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
  145. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
  146. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
  147. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
  148. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
  149. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
  150. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
  151. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
  152. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
  153. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
  154. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
  155. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
  156. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
  157. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
  158. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
  159. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
  160. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
  161. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -968
  162. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
  163. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
  164. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
  165. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
  166. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
  167. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
  168. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
  169. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
  170. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +212 -0
  171. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
  172. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
  173. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +169 -0
  174. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
  175. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -765
  176. package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
  177. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
  178. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
  179. package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
  180. package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
  181. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +93 -0
  182. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
  183. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
  184. package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
  185. package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
  186. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -821
  187. package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
  188. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +68 -0
  189. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +169 -0
  190. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +182 -0
  191. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
  192. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +167 -0
  193. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +22 -10
  194. package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
  195. package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
  196. package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
  197. package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
  198. package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
  199. package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
  200. package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
  201. package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
  202. package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
  203. package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
  204. package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
  205. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
  206. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
  207. package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
  208. package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
  209. package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
  210. package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
  211. package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
  212. package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
  213. package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
  214. package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
  215. package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
  216. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
  217. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
  218. package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
  219. package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
  220. package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
  221. package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
  222. package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
  223. package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
  224. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
  225. package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
  226. package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
  227. package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
  228. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -157
  229. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  230. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +197 -99
  231. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
  232. package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
  233. package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
  234. package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
  235. package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
  236. package/dist/extensions/agent-browser/lib/page-target-validation.js +55 -246
  237. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  238. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +133 -68
  239. package/dist/extensions/agent-browser/lib/playbook.js +16 -12
  240. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  241. package/dist/extensions/agent-browser/lib/process-environment.js +13 -6
  242. package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
  243. package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
  244. package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
  245. package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
  246. package/dist/extensions/agent-browser/lib/process.js +145 -536
  247. package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
  248. package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
  249. package/dist/extensions/agent-browser/lib/read-command.js +41 -0
  250. package/dist/extensions/agent-browser/lib/read-confirmation.js +131 -68
  251. package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
  252. package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
  253. package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
  254. package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
  255. package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
  256. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
  257. package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
  258. package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
  259. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
  260. package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
  261. package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
  262. package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -13
  263. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
  264. package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
  265. package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
  266. package/dist/extensions/agent-browser/lib/results/envelope.js +90 -67
  267. package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
  268. package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
  269. package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
  270. package/dist/extensions/agent-browser/lib/results/network.js +35 -12
  271. package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
  272. package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
  273. package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
  274. package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
  275. package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
  276. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -555
  277. package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
  278. package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
  279. package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
  280. package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
  281. package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
  282. package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
  283. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
  284. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
  285. package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
  286. package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
  287. package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
  288. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
  289. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
  290. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
  291. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
  292. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
  293. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
  294. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
  295. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
  296. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
  297. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
  298. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1052
  299. package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
  300. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
  301. package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
  302. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
  303. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
  304. package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
  305. package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
  306. package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
  307. package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
  308. package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
  309. package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
  310. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +116 -240
  311. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
  312. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +109 -73
  313. package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
  314. package/dist/extensions/agent-browser/lib/results/presentation.js +17 -261
  315. package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
  316. package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
  317. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
  318. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
  319. package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
  320. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +119 -119
  321. package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
  322. package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
  323. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
  324. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
  325. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
  326. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
  327. package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
  328. package/dist/extensions/agent-browser/lib/results/text.js +16 -5
  329. package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
  330. package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
  331. package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
  332. package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
  333. package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
  334. package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
  335. package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
  336. package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
  337. package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
  338. package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
  339. package/dist/extensions/agent-browser/lib/runtime.js +137 -1041
  340. package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
  341. package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
  342. package/dist/extensions/agent-browser/lib/session-page-state.js +178 -333
  343. package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
  344. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +81 -0
  345. package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
  346. package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
  347. package/dist/extensions/agent-browser/lib/temp-root.js +211 -0
  348. package/dist/extensions/agent-browser/lib/temp.js +33 -446
  349. package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
  350. package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
  351. package/dist/extensions/agent-browser/lib/web-search-providers.js +193 -0
  352. package/dist/extensions/agent-browser/lib/web-search-request.js +102 -0
  353. package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
  354. package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
  355. package/dist/extensions/agent-browser/lib/web-search.js +124 -614
  356. package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
  357. package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
  358. package/dist/extensions/agent-browser/script-worker.js +80 -43
  359. package/dist/scripts/agent-browser-target.mjs +4 -2
  360. package/docs/ARCHITECTURE.md +19 -6
  361. package/docs/CODE_QUALITY.md +267 -0
  362. package/docs/COMMAND_REFERENCE.md +272 -241
  363. package/docs/ELECTRON.md +77 -46
  364. package/docs/REFERENCE.md +869 -0
  365. package/docs/RELEASE.md +25 -22
  366. package/docs/REQUIREMENTS.md +2 -1
  367. package/docs/SUPPORT_MATRIX.md +81 -79
  368. package/docs/TOOL_CONTRACT.md +158 -125
  369. package/docs/platform-smoke.md +8 -8
  370. package/package.json +144 -120
  371. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  372. package/scripts/agent-browser-target.mjs +6 -2
  373. package/scripts/build.mjs +37 -8
  374. package/scripts/capability-core-commands.mjs +193 -0
  375. package/scripts/capability-options.mjs +283 -0
  376. package/scripts/capability-samples.mjs +133 -0
  377. package/scripts/capability-section.mjs +11 -0
  378. package/scripts/config.mjs +235 -132
  379. package/scripts/convert-browser-session.mjs +30 -9
  380. package/scripts/doctor-sources.mjs +195 -0
  381. package/scripts/doctor.mjs +94 -249
  382. package/scripts/platform-smoke/artifacts.mjs +38 -11
  383. package/scripts/platform-smoke/commands.mjs +104 -0
  384. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  385. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  386. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  387. package/scripts/platform-smoke/doctor.mjs +212 -320
  388. package/scripts/platform-smoke/lease-evidence.mjs +132 -0
  389. package/scripts/platform-smoke/linux-image/Dockerfile +8 -2
  390. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  391. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  392. package/scripts/platform-smoke/targets.mjs +154 -472
  393. package/scripts/platform-smoke.mjs +55 -40
  394. package/scripts/prepare.mjs +16 -7
@@ -1,975 +1,25 @@
1
1
  import { rm } from "node:fs/promises";
2
- import { observeNativeWebMcp } from "../../webmcp-observation.js";
3
- import { parseArgvDescriptor } from "../../argv-descriptor.js";
4
- import { isBrowserIndependentRead, needsManagedSession } from "../../command-policy.js";
5
- import { deleteIdentityKeysInNamespace, getAgentBrowserSessionIdentityKey, getBooleanFlagValue, isAgentBrowserSessionIdentityKeyInNamespace } from "../../argv-grammar.js";
6
- import { batchHasSuccessfulCloseAll, getSuccessfulBatchCloseLifecycle } from "../../batch-lifecycle.js";
7
- import { isCloseAllCommand, isCloseCommand, isNavigationObservableCommandName, isOpenNavigationCommand, isPageMutationCommand, isRecordPageTransitionCommand, isUnverifiedPageTransitionCommand, isWindowOrDiffPageTransitionCommand } from "../../command-taxonomy.js";
8
- import { OPEN_RESULT_TAB_CORRECTION_FLAGS } from "../../launch-scoped-flags.js";
9
- import { cleanupElectronLaunchResources, inspectElectronLaunchStatus } from "../../electron/cleanup.js";
10
- import { getResultingPageTargetState, commandRequiresLivePageVerification } from "../../page-target-validation.js";
11
- import { analyzeNetworkSourceLookupResults, analyzeSourceLookupResults, redactNetworkSourceLookupAnalysis } from "../../input-modes/lookups.js";
12
- import { analyzeQaPresetResults, analyzeQaPresetTimeout, buildQaCompactFailureText, buildQaCompactPassText, extractQaPageContext } from "../../input-modes/job.js";
13
- import { applyNetworkRouteRecords, buildNetworkRouteDiagnostics } from "../../results/network-routes.js";
14
- import { buildToolPresentation } from "../../results/presentation.js";
15
- import { compactLargePresentationOutput } from "../../results/presentation/large-output.js";
16
- import { extractEnvelopeErrorText, getAgentBrowserErrorText, parseAgentBrowserEnvelope } from "../../results/envelope.js";
17
- import { detectConfirmationRequired } from "../../results/confirmation.js";
18
- import { extractAgentBrowserLifecycle, omitUpstreamLifecycle } from "../../results/presentation/common.js";
19
- import { getClipboardWritePayloadCandidates, redactClipboardPermissionEcho, redactClipboardPermissionErrorValue } from "../../results/presentation/errors.js";
20
- import { shouldCaptureSemanticActionNavigationSummary } from "../../results/presentation/semantic-action.js";
21
- import { buildPageTransitionRefSnapshotInvalidation, commandExplicitlyTargetsAboutBlank, getCommandRefSnapshotInvalidation, deriveSessionTabTarget, extractLatestRefSnapshotStateFromBatchResults, extractRefSnapshotFromData, extractSessionTabTargetFromBatchResults, extractSessionTabTargetFromCommandData, isAboutBlankSessionTabTarget, normalizeSessionTabTarget, } from "../../session-page-state.js";
22
- import { isRecord } from "../../parsing.js";
23
- import { getAgentBrowserProcessEnvironment } from "../../process-environment.js";
24
- import { buildReadConfirmationNextActions, isBrowserIndependentConfirmation, isSuccessfulNativeConfirmedClose, nextReadConfirmation, parseReadConfirmation } from "../../read-confirmation.js";
25
- import { pruneOwnedManagedSessionRestoreSnapshots } from "../../managed-session-restore.js";
26
- import { isManagedSessionRestoreKey } from "../../managed-session-storage.js";
27
- import { createFreshSessionName, extractUpstreamCommandTokens, redactInvocationArgs, resolveManagedSessionState } from "../../runtime.js";
28
- import { getUpstreamEffectiveBatchSteps } from "../batch-stdin.js";
29
- import { closeManagedSession, inspectManagedSessionDaemon } from "./managed-session-daemon-policy.js";
30
- import { applyOpenResultTabCorrection, applyBrowserRunStatePatch, buildAboutBlankRecoveryHint, buildAboutBlankWarning, buildElectronPostCommandHealthDiagnostic, buildElectronRefFreshnessDiagnostic, buildElectronSessionMismatch, buildManagedSessionOutcome, collectOpenResultTabCorrection, collectSessionTabSelection, collectSessionTabTarget, commandChoosesSessionTabTarget, extractNavigationSummaryFromData, extractStringResultField, findElectronLaunchRecordForSession, formatElectronPostCommandHealthText, formatElectronSessionMismatchText, getSessionContextKey, getStaleRefArgs, mergeNavigationSummaryIntoData, runSessionCommandData, shouldCaptureNavigationSummary, shouldCorrectSessionTabAfterCommand, shouldInspectElectronPostCommandHealth, updateTraceOwnerState, } from "./session-state.js";
31
- import { collectClickDispatchDiagnostic } from "./click-dispatch.js";
32
- import { buildScrollNoopDiagnostic, collectComboboxFocusDiagnostic, collectElectronBroadGetTextScopeDiagnostics, collectElectronHandoff, collectFillVerificationDiagnostic, collectNavigationSummary, collectOverlayBlockerDiagnostic, collectQaAttachedTarget, collectSnapshotOverlayBlockerDiagnostic, collectRecordingDependencyWarning, collectScrollPositionSnapshot, collectSelectorTextVisibilityDiagnostics, collectTimeoutPartialProgress, sleepMs, formatQaAttachedTargetText, getArtifactCleanupGuidance, getEvalResultWarning, getEvalStdinHint, getSourceLookupElectronContext, } from "./diagnostics.js";
33
- import { repairScreenshotData } from "./prepare.js";
34
- import { mergeRecordingRecoveryPresentation, recoverRecordingStop } from "./recording-recovery.js";
35
- import { getPersistentSessionArtifactStore } from "./session-state.js";
36
- import { nativePolicyDefinitelyUnestablished } from "./session-state.js";
37
- import { buildFinalAgentBrowserToolResult, buildRedactedPresentationContent, buildWrapperRecoveryHint, prepareFinalResultRecoveryState, redactExactSensitiveValue, } from "./final-result.js";
38
- async function repairScreenshotArtifact(options) {
39
- const { cwd, envelope, request } = options;
40
- if (!request || !envelope || !isRecord(envelope.data))
41
- return { envelope, request };
42
- const repaired = await repairScreenshotData({ cwd, data: envelope.data, request });
43
- return { envelope: { ...envelope, data: repaired.data }, request: repaired.request };
44
- }
45
- async function repairBatchScreenshotArtifacts(options) {
46
- const { cwd, envelope, requests } = options;
47
- if (!envelope || !Array.isArray(envelope.data) || !requests?.some((request) => request !== undefined))
48
- return { envelope, requests };
49
- const repairedRequests = [];
50
- const repairedData = await Promise.all(envelope.data.map(async (item, index) => {
51
- const request = requests[index];
52
- if (!request || !isRecord(item) || !isRecord(item.result))
53
- return item;
54
- const repaired = await repairScreenshotData({ cwd, data: item.result, request });
55
- repairedRequests[index] = repaired.request;
56
- return { ...item, result: repaired.data };
57
- }));
58
- return { envelope: { ...envelope, data: repairedData }, requests: repairedRequests };
59
- }
60
- function getEnvelopeErrorString(envelope) {
61
- if (!envelope?.error)
62
- return undefined;
63
- if (typeof envelope.error === "string")
64
- return envelope.error;
65
- if (isRecord(envelope.error) && typeof envelope.error.message === "string")
66
- return envelope.error.message;
67
- return String(envelope.error);
68
- }
69
- function isStreamEnableAlreadyEnabledNoop(options) {
70
- if (!options.processSucceeded || options.command !== "stream" || options.subcommand !== "enable" || options.envelope?.success !== false)
71
- return false;
72
- const message = (getEnvelopeErrorString(options.envelope) ?? "").trim().replace(/[.!]+$/, "").toLowerCase();
73
- return message === "streaming is already enabled for this session" || message === "streaming is already enabled" || message === "stream already enabled";
74
- }
75
- function isPendingWebMcpMutation(command, subcommand, data) {
76
- return command === "webmcp"
77
- && ["invoke", "result"].includes(subcommand ?? "")
78
- && isRecord(data)
79
- && data.status === "pending";
80
- }
81
- function isWebMcpSettlementCommand(command, subcommand) {
82
- return command === "webmcp" && ["result", "cancel"].includes(subcommand ?? "");
83
- }
84
- function batchHasPendingWebMcpMutation(data) {
85
- if (!Array.isArray(data))
86
- return false;
87
- return data.some((row) => {
88
- if (!isRecord(row) || row.success === false || !Array.isArray(row.command) || !row.command.every((token) => typeof token === "string"))
89
- return false;
90
- const [command, subcommand] = extractUpstreamCommandTokens(row.command);
91
- return isPendingWebMcpMutation(command, subcommand, row.result);
92
- });
93
- }
94
- function batchHasFailedWebMcpSettlement(data) {
95
- if (!Array.isArray(data))
96
- return false;
97
- return data.some((row) => {
98
- if (!isRecord(row) || row.success !== false || !Array.isArray(row.command) || !row.command.every((token) => typeof token === "string"))
99
- return false;
100
- const [command, subcommand] = extractUpstreamCommandTokens(row.command);
101
- return isWebMcpSettlementCommand(command, subcommand);
102
- });
103
- }
104
- function batchStartedManagedBrowser(data) {
105
- if (!Array.isArray(data))
106
- return false;
107
- return data.some((entry) => {
108
- if (!isRecord(entry) || entry.success !== true || !Array.isArray(entry.command))
109
- return false;
110
- const command = typeof entry.command[0] === "string" ? entry.command[0] : undefined;
111
- return command === "connect" || command === "goto" || command === "navigate" || isOpenNavigationCommand(command);
112
- });
113
- }
114
- function withoutNamespaceEntries(entries, namespace) {
115
- return new Map([...entries].filter(([key]) => !isAgentBrowserSessionIdentityKeyInNamespace(key, namespace)));
116
- }
117
- function setNetworkRouteState(options) {
118
- if (!options.sessionName)
119
- return options.routesBySession;
120
- const previousRoutes = options.routesBySession.get(options.sessionName);
121
- if (options.routes === previousRoutes)
122
- return options.routesBySession;
123
- const next = new Map(options.routesBySession);
124
- if (options.routes && options.routes.length > 0)
125
- next.set(options.sessionName, options.routes);
126
- else
127
- next.delete(options.sessionName);
128
- return next;
129
- }
130
- function applyNetworkRouteState(options) {
131
- const routes = options.sessionName ? applyNetworkRouteRecords(options.routesBySession.get(options.sessionName), options.commandTokens, options.succeeded) : undefined;
132
- return setNetworkRouteState({ routes, routesBySession: options.routesBySession, sessionName: options.sessionName });
133
- }
134
- function applyBatchNetworkRouteState(options) {
135
- if (!options.succeeded || !options.sessionName || !Array.isArray(options.data))
136
- return options.routesBySession;
137
- let routes = options.routesBySession.get(options.sessionName);
138
- for (const item of options.data) {
139
- if (!isRecord(item) || !Array.isArray(item.command) || !item.command.every((token) => typeof token === "string"))
140
- continue;
141
- const commandTokens = extractUpstreamCommandTokens(item.command);
142
- const stepSucceeded = item.success !== false && !detectConfirmationRequired(item.result);
143
- if (stepSucceeded && isCloseCommand(commandTokens[0]))
144
- routes = undefined;
145
- else
146
- routes = applyNetworkRouteRecords(routes, commandTokens, stepSucceeded);
147
- }
148
- return setNetworkRouteState({ routes, routesBySession: options.routesBySession, sessionName: options.sessionName });
149
- }
2
+ import { captureBrowserOutputOwnership } from "./process-output-ownership.js";
3
+ import { observeNativeEffects } from "./process-output-native-phase.js";
4
+ import { observePageEffects } from "./process-output-page-phase.js";
5
+ import { commitLifecycleEffects } from "./process-output-lifecycle-phase.js";
6
+ import { publishOutputEffects } from "./process-output-publication-phase.js";
7
+ import { buildOutputResult } from "./process-output-publication.js";
150
8
  export async function processBrowserOutput(input) {
151
- const { ctx, cwd, electronPostCommandStatusSettleMs, implicitSessionCloseTimeoutMs, sessionPageStateUpdate, signal, state } = input;
152
- const operationCwd = input.operationCwd ?? cwd;
153
- const { prepared, processResult } = input;
154
- const { electronChildProcesses, electronLaunchRecords, sessionPageState, traceOwners } = state;
155
- let artifactManifest = state.artifactManifest;
156
- let freshSessionOrdinal = state.freshSessionOrdinal;
157
- let managedSessionActive = state.managedSessionActive;
158
- let managedSessionCompatibilityWorkaround = state.managedSessionCompatibilityWorkaround;
159
- let managedSessionHeadedAutosaveDisabled = state.managedSessionHeadedAutosaveDisabled === true;
160
- let managedSessionHeadedAutosaveInterval = state.managedSessionHeadedAutosaveInterval;
161
- let managedSessionCwd = state.managedSessionCwd;
162
- let managedSessionName = state.managedSessionName;
163
- let managedSessionNamespace = state.managedSessionNamespace;
164
- let networkRoutesBySession = state.networkRoutesBySession;
9
+ const ownership = captureBrowserOutputOwnership(input);
165
10
  try {
166
- const persistentArtifactStore = getPersistentSessionArtifactStore(ctx);
167
- // Native upgrade prints text even with --json; explicit false selects opaque native text.
168
- const plainTextUpgrade = !prepared.executionPlan.plainTextInspection && prepared.executionPlan.commandInfo.command === "upgrade" && !needsManagedSession(parseArgvDescriptor(prepared.runtimeToolArgs));
169
- const textOutput = getBooleanFlagValue(prepared.processArgs, "--json") === false;
170
- const parsed = await parseAgentBrowserEnvelope({ stdout: processResult.stdout, stdoutPath: processResult.stdoutSpillPath, plainText: plainTextUpgrade, textOutput });
171
- observeNativeWebMcp(parsed.envelope?.data);
172
- let parseError = parsed.parseError;
173
- const recordingStopRecovery = await recoverRecordingStop({
174
- modelVisible: input.modelVisible,
175
- artifactManifest, artifactRunStartedAtMs: input.artifactRunStartedAtMs, commandTokens: prepared.commandTokens, cwd,
176
- envelope: parsed.envelope, namespace: prepared.executionPlan.namespace, parseError, processResult,
177
- reservation: prepared.executionPlan.sessionName ? state.activeRecordingReservations?.get(getAgentBrowserSessionIdentityKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace)) : undefined,
178
- sessionName: prepared.executionPlan.sessionName, signal, stdin: prepared.runtimeToolStdin,
179
- });
180
- let presentationEnvelope = recordingStopRecovery?.envelope ?? parsed.envelope;
181
- let navigationSummary = undefined;
182
- let failedTransitionReverification = false;
183
- const repairedScreenshot = await repairScreenshotArtifact({ cwd, envelope: presentationEnvelope, request: prepared.preparedArgs.screenshotPathRequest });
184
- presentationEnvelope = repairedScreenshot.envelope;
185
- const repairedBatchScreenshots = await repairBatchScreenshotArtifacts({ cwd, envelope: presentationEnvelope, requests: prepared.preparedArgs.batchScreenshotPathRequests });
186
- presentationEnvelope = repairedBatchScreenshots.envelope;
187
- const screenshotArtifactRequest = repairedScreenshot.request;
188
- const batchScreenshotArtifactRequests = repairedBatchScreenshots.requests;
189
- const batchCommandSteps = prepared.executionPlan.commandInfo.command === "batch"
190
- ? getUpstreamEffectiveBatchSteps(prepared.commandTokens, prepared.runtimeToolStdin)
191
- : [];
192
- const dispatchedCommands = prepared.executionPlan.commandInfo.command !== "batch"
193
- ? [prepared.commandTokens]
194
- : Array.isArray(presentationEnvelope?.data)
195
- ? presentationEnvelope.data.flatMap((row, index) => isRecord(row) ? [Array.isArray(row.command) && row.command.every((token) => typeof token === "string") ? row.command : batchCommandSteps[index] ?? []] : [])
196
- : batchCommandSteps;
197
- const confirmationSessionName = prepared.executionPlan.sessionName ?? "default";
198
- let readConfirmation = state.sessionPageState.getReadConfirmation(getAgentBrowserSessionIdentityKey(confirmationSessionName, prepared.executionPlan.namespace));
199
- let readConfirmationEvent;
200
- const confirmedEffects = [];
201
- const confirmationRows = prepared.executionPlan.commandInfo.command === "batch" && Array.isArray(presentationEnvelope?.data)
202
- ? presentationEnvelope.data.flatMap((row, index) => isRecord(row) ? [{ tokens: Array.isArray(row.command) && row.command.every(token => typeof token === "string") ? row.command : batchCommandSteps[index] ?? [], data: row.result, index, response: row, succeeded: row.success === true }] : [])
203
- : [{ tokens: prepared.commandTokens, data: presentationEnvelope?.data, index: 0, response: presentationEnvelope, succeeded: presentationEnvelope?.success === true }];
204
- for (const row of confirmationRows) {
205
- if (readConfirmation?.state === "pending" && readConfirmation.source === "native-guarded-action" && typeof readConfirmation.command === "string"
206
- && row.tokens.length === 2 && row.tokens[0] === "confirm" && row.tokens[1] === readConfirmation.id
207
- && isRecord(row.data) && row.data.confirmed === true && row.data.action === readConfirmation.action
208
- && isRecord(row.data.result) && !detectConfirmationRequired(row.data)) {
209
- confirmedEffects.push({ command: readConfirmation.command, data: row.data.result.data, index: row.index, succeeded: row.succeeded && row.data.result.success === true });
210
- }
211
- const transition = nextReadConfirmation({ commandTokens: row.tokens, current: readConfirmation, data: row.data, namespace: prepared.executionPlan.namespace, sessionName: confirmationSessionName, succeeded: row.succeeded });
212
- if (transition) {
213
- readConfirmationEvent = transition;
214
- readConfirmation = transition;
215
- }
216
- if (row.tokens.length === 2 && row.tokens[0] === "confirm" && isRecord(row.data) && row.data.confirmed === true && isRecord(row.data.result) && row.data.result.success === false && row.response) {
217
- row.response.success = false;
218
- row.response.error = row.data.result.error;
219
- if (presentationEnvelope)
220
- presentationEnvelope.success = false;
221
- }
222
- }
223
- const confirmedData = prepared.commandTokens[0] === "confirm" ? confirmedEffects[0]?.data : undefined;
224
- const confirmedCommand = prepared.commandTokens[0] === "confirm" ? confirmedEffects[0]?.command : undefined;
225
- const directClose = isCloseCommand(prepared.executionPlan.commandInfo.command)
226
- || isSuccessfulNativeConfirmedClose(prepared.commandTokens, presentationEnvelope?.data);
227
- if (readConfirmationEvent?.state === "pending")
228
- state.observedBrowserEffects = { ...state.observedBrowserEffects, readConfirmation: readConfirmationEvent };
229
- const destinationTransition = dispatchedCommands.some((step) => {
230
- const [command, subcommand] = extractUpstreamCommandTokens(step);
231
- return isWindowOrDiffPageTransitionCommand(command, subcommand);
232
- });
233
- const nestedBatchClose = prepared.executionPlan.commandInfo.command === "batch"
234
- ? getSuccessfulBatchCloseLifecycle(presentationEnvelope?.data, batchCommandSteps)
235
- : undefined;
236
- const nestedBatchClosed = nestedBatchClose?.endsClosed === true;
237
- const nestedBatchRemainsActive = nestedBatchClose?.endsClosed === false;
238
- const nestedBatchClosesAll = prepared.executionPlan.commandInfo.command === "batch"
239
- && batchHasSuccessfulCloseAll(presentationEnvelope?.data, batchCommandSteps);
240
- const directCloseAllRequested = isCloseAllCommand(extractUpstreamCommandTokens(prepared.commandTokens));
241
- const directCloseData = confirmedData ?? presentationEnvelope?.data;
242
- const rawCloseStatePath = directClose && isRecord(directCloseData) && typeof directCloseData.statePath === "string"
243
- ? directCloseData.statePath
244
- : nestedBatchClose?.statePath;
245
- if (presentationEnvelope && prepared.exactSensitiveValues.length > 0)
246
- presentationEnvelope = redactExactSensitiveValue(presentationEnvelope, prepared.exactSensitiveValues);
247
- const parseFailureOutput = parseError && processResult.stdoutSpillPath
248
- ? { fullOutputUnavailable: "Malformed upstream output was discarded because it may contain sensitive browser data." }
249
- : {};
250
- const browserIndependentRead = isBrowserIndependentConfirmation(prepared.readConfirmation) || isBrowserIndependentRead(prepared.commandTokens, prepared.runtimeToolStdin);
251
- const nativeCommandMayHaveExecuted = !nativePolicyDefinitelyUnestablished(processResult, parsed.envelope, prepared.commandTokens);
252
- if (state.confirmationPolicyMayBeEstablished !== true)
253
- state.confirmationPolicyMayBeEstablished = nativeCommandMayHaveExecuted;
254
- const processSucceeded = !processResult.timedOut && !processResult.aborted && !processResult.spawnError && processResult.exitCode === 0;
255
- const plainTextInspection = prepared.executionPlan.plainTextInspection && processSucceeded;
256
- const parseSucceeded = plainTextInspection || parseError === undefined;
257
- if (isStreamEnableAlreadyEnabledNoop({ command: prepared.executionPlan.commandInfo.command, envelope: presentationEnvelope, processSucceeded, subcommand: prepared.executionPlan.commandInfo.subcommand })) {
258
- presentationEnvelope = { success: true, data: { alreadyEnabled: true, enabled: true, message: getEnvelopeErrorString(presentationEnvelope) ?? "Stream already enabled" } };
259
- }
260
- const envelopeSuccess = plainTextInspection ? true : presentationEnvelope?.success !== false && !detectConfirmationRequired(presentationEnvelope?.data);
261
- let succeeded = (processSucceeded && parseSucceeded && envelopeSuccess) || recordingStopRecovery?.recovery.healed === true;
262
- const inspectionText = plainTextInspection ? processResult.stdout.trim() : undefined;
263
- const unobservedMutation = processResult.agentBrowserStarted && !plainTextInspection
264
- && (processResult.aborted || processResult.timedOut || !parseSucceeded || presentationEnvelope === undefined)
265
- && (prepared.executionPlan.commandInfo.command === "batch" ? batchCommandSteps : [prepared.commandTokens]).some(step => {
266
- const action = step[0] === "find" ? step[step[1] === "nth" ? 4 : 3] ?? "click" : step[0];
267
- return isPageMutationCommand(action, step[1]);
268
- });
269
- const sessionStateKey = getSessionContextKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace);
270
- const closeAllApplied = nestedBatchClosesAll || (directCloseAllRequested && succeeded);
271
- if (sessionStateKey && processResult.agentBrowserStarted && sessionPageState.get(sessionStateKey).tabReopenPending === true) {
272
- if (dispatchedCommands.some(commandChoosesSessionTabTarget))
273
- sessionPageState.setTabReopenPending({ pending: false, sessionName: sessionStateKey, update: sessionPageStateUpdate });
274
- }
275
- if (closeAllApplied) {
276
- networkRoutesBySession = withoutNamespaceEntries(networkRoutesBySession, prepared.executionPlan.namespace);
277
- deleteIdentityKeysInNamespace(state.attachedSessionKeys, prepared.executionPlan.namespace);
278
- deleteIdentityKeysInNamespace(traceOwners, prepared.executionPlan.namespace);
279
- sessionPageState.clearNamespace(prepared.executionPlan.namespace);
280
- const retainedSessionKey = nestedBatchRemainsActive ? sessionStateKey : undefined;
281
- for (const [key, owner] of state.ownedManagedSessions) {
282
- if (!isAgentBrowserSessionIdentityKeyInNamespace(key, prepared.executionPlan.namespace) || key === retainedSessionKey)
283
- continue;
284
- state.closedManagedSessionNames.add(key);
285
- state.managedSessionRestoreState.clear(owner.sessionName, owner.namespace);
286
- }
287
- }
288
- else if (nestedBatchClose && sessionStateKey) {
289
- networkRoutesBySession = new Map(networkRoutesBySession);
290
- networkRoutesBySession.delete(sessionStateKey);
291
- sessionPageState.clearSession(sessionStateKey);
292
- }
293
- if (sessionStateKey && nestedBatchRemainsActive) {
294
- const confirmActions = getAgentBrowserProcessEnvironment().AGENT_BROWSER_CONFIRM_ACTIONS;
295
- if (confirmActions !== undefined)
296
- sessionPageState.setConfirmActions(sessionStateKey, confirmActions);
297
- }
298
- if (prepared.executionPlan.commandInfo.command === "batch" && Array.isArray(presentationEnvelope?.data)) {
299
- for (const [index, row] of presentationEnvelope.data.entries()) {
300
- if (!isRecord(row))
301
- continue;
302
- const rowCommand = Array.isArray(row.command) && row.command.every((token) => typeof token === "string")
303
- ? row.command
304
- : batchCommandSteps[index];
305
- if (!rowCommand)
306
- continue;
307
- const [command, subcommand] = extractUpstreamCommandTokens(rowCommand);
308
- updateTraceOwnerState({ command, sessionName: sessionStateKey, subcommand, succeeded: row.success === true && !detectConfirmationRequired(row.result), traceOwners });
309
- }
310
- }
311
- else {
312
- updateTraceOwnerState({ command: directClose ? "close" : prepared.executionPlan.commandInfo.command, sessionName: sessionStateKey, subcommand: prepared.executionPlan.commandInfo.subcommand, succeeded, traceOwners });
313
- }
314
- let clickDispatchDiagnostic;
315
- if (succeeded && prepared.clickDispatchProbe) {
316
- clickDispatchDiagnostic = await collectClickDispatchDiagnostic({ cwd, namespace: prepared.executionPlan.namespace, probe: prepared.clickDispatchProbe, sessionName: prepared.executionPlan.sessionName, signal });
317
- if (clickDispatchDiagnostic) {
318
- succeeded = false;
319
- presentationEnvelope = { ...(presentationEnvelope ?? {}), error: clickDispatchDiagnostic.summary, success: false };
320
- }
321
- }
322
- const tabTransition = confirmedEffects.some(effect => effect.command === "tab") || dispatchedCommands.some((step) => {
323
- const [command, subcommand] = extractUpstreamCommandTokens(step);
324
- return command === "tab" && subcommand !== undefined && subcommand !== "list";
325
- });
326
- // Non-page rows (including a failed prefix) cannot retire a cold target for a navigation that never ran.
327
- const resultingPageState = !nativeCommandMayHaveExecuted || detectConfirmationRequired(presentationEnvelope?.data) || sessionPageState.get(sessionStateKey).tabReopenPending === true
328
- ? { currentPageUrl: prepared.priorSessionTabTarget?.url, pageTargetMayHaveChanged: false, pageUrlUnknown: prepared.priorSessionTabTargetUnknown === true }
329
- : getResultingPageTargetState({
330
- args: prepared.executionPlan.effectiveArgs,
331
- executedBatchSteps: dispatchedCommands,
332
- batchResults: presentationEnvelope?.data,
333
- currentPageUrl: prepared.priorSessionTabTarget?.url,
334
- pageUrlUnknown: prepared.priorSessionTabTargetUnknown === true,
335
- });
336
- if ((succeeded || processSucceeded && confirmedEffects.some(effect => effect.succeeded)) && readConfirmation?.state !== "pending" && !nestedBatchClosed && !directClose &&
337
- (confirmedEffects.some(effect => shouldCaptureNavigationSummary(effect.command, effect.data)) || shouldCaptureNavigationSummary(prepared.executionPlan.commandInfo.command, presentationEnvelope?.data, prepared.executionPlan.commandInfo.subcommand) ||
338
- (prepared.executionPlan.commandInfo.command === "batch" && dispatchedCommands.some(([command, subcommand]) => isNavigationObservableCommandName(command, subcommand))) ||
339
- shouldCaptureSemanticActionNavigationSummary(prepared.compiledSemanticAction, presentationEnvelope?.data) ||
340
- commandRequiresLivePageVerification(prepared.executionPlan.effectiveArgs, prepared.runtimeToolStdin) ||
341
- destinationTransition || tabTransition)) {
342
- navigationSummary = await collectNavigationSummary({ cwd, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, reusePriorTitle: !tabTransition, sessionName: prepared.executionPlan.sessionName, signal });
343
- }
344
- // Failed transitions may already have changed the page; keep only a live observed URL.
345
- if (succeeded === false && navigationSummary === undefined && readConfirmation?.state !== "pending" &&
346
- processResult.agentBrowserStarted && nativeCommandMayHaveExecuted &&
347
- !processResult.aborted &&
348
- !processResult.timedOut &&
349
- !nestedBatchClosed && !directClose &&
350
- (confirmedEffects.some(effect => isUnverifiedPageTransitionCommand(effect.command)) || dispatchedCommands.some((step) => {
351
- const [command, subcommand] = extractUpstreamCommandTokens(step);
352
- return (prepared.executionPlan.commandInfo.command === "batch" && isOpenNavigationCommand(command))
353
- || isUnverifiedPageTransitionCommand(command, subcommand);
354
- }))) {
355
- navigationSummary = await collectNavigationSummary({ cwd, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName, signal });
356
- // Re-verifying a failed transition's URL does not make its prior refs valid.
357
- failedTransitionReverification = navigationSummary !== undefined;
358
- }
359
- if (!textOutput && navigationSummary && presentationEnvelope && prepared.executionPlan.commandInfo.command !== "eval" && !Array.isArray(presentationEnvelope.data))
360
- presentationEnvelope = { ...presentationEnvelope, data: mergeNavigationSummaryIntoData(presentationEnvelope.data, navigationSummary) };
361
- let overlayBlockerDiagnostic;
362
- let openResultTabCorrection;
363
- if (succeeded && prepared.executionPlan.sessionName && prepared.executionPlan.startupScopedFlags.some((flag) => OPEN_RESULT_TAB_CORRECTION_FLAGS.has(flag)) && isOpenNavigationCommand(prepared.executionPlan.commandInfo.command) && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens)) {
364
- const targetTitle = extractStringResultField(presentationEnvelope?.data, "title");
365
- const targetUrl = extractStringResultField(presentationEnvelope?.data, "url");
366
- const plannedTabCorrection = await collectOpenResultTabCorrection({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, targetTitle, targetUrl });
367
- if (plannedTabCorrection)
368
- openResultTabCorrection = await applyOpenResultTabCorrection({ correction: plannedTabCorrection, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal });
369
- }
370
- const verifiesCurrentUrl = prepared.executionPlan.commandInfo.command === "get" && prepared.executionPlan.commandInfo.subcommand === "url"
371
- || readConfirmationEvent?.state === "cleared" && prepared.readConfirmation?.source === "native-guarded-action" && extractSessionTabTargetFromCommandData(prepared.commandTokens, presentationEnvelope?.data) !== undefined;
372
- const trustsReportedPageTarget = !resultingPageState.pageUrlUnknown || verifiesCurrentUrl;
373
- const pendingWebMcpMutation = isPendingWebMcpMutation(prepared.executionPlan.commandInfo.command, prepared.executionPlan.commandInfo.subcommand, presentationEnvelope?.data) || (prepared.executionPlan.commandInfo.command === "batch" && batchHasPendingWebMcpMutation(presentationEnvelope?.data));
374
- const failedWebMcpSettlement = prepared.priorSessionTabTargetUnknown === true && ((!succeeded && isWebMcpSettlementCommand(prepared.executionPlan.commandInfo.command, prepared.executionPlan.commandInfo.subcommand))
375
- || (prepared.executionPlan.commandInfo.command === "batch" && batchHasFailedWebMcpSettlement(presentationEnvelope?.data)));
376
- const unsettledWebMcpMutation = pendingWebMcpMutation || failedWebMcpSettlement;
377
- const helperConfirmation = parseReadConfirmation(state.observedBrowserEffects?.readConfirmation);
378
- // Main pending installs this object above; only a helper can replace it during post-processing.
379
- let confirmationFromHelper = state.observedBrowserEffects?.readConfirmation !== readConfirmationEvent;
380
- if (confirmationFromHelper && helperConfirmation?.state === "pending") {
381
- readConfirmationEvent = helperConfirmation;
382
- readConfirmation = helperConfirmation;
383
- succeeded = false;
384
- }
385
- const pageTargetData = textOutput ? undefined : presentationEnvelope?.data;
386
- let observedSessionTabTarget = unsettledWebMcpMutation || (unobservedMutation && !failedTransitionReverification)
387
- ? undefined
388
- : normalizeSessionTabTarget(navigationSummary)
389
- ?? (trustsReportedPageTarget ? extractSessionTabTargetFromBatchResults(pageTargetData) : undefined)
390
- ?? (succeeded && trustsReportedPageTarget ? extractSessionTabTargetFromCommandData(prepared.commandTokens, pageTargetData) : undefined);
391
- if (observedSessionTabTarget && readConfirmation?.state !== "pending" && !browserIndependentRead && !nestedBatchClosed && !directClose) {
392
- const reportedTarget = prepared.executionPlan.commandInfo.command === "batch"
393
- ? extractSessionTabTargetFromBatchResults(pageTargetData)
394
- : prepared.commandTokens[0] === "tab" && prepared.commandTokens[1] === "close" ? undefined
395
- : extractSessionTabTargetFromCommandData(prepared.commandTokens, pageTargetData);
396
- if (reportedTarget?.targetId)
397
- observedSessionTabTarget.targetId = reportedTarget.targetId;
398
- else
399
- observedSessionTabTarget = await collectSessionTabTarget({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, target: observedSessionTabTarget });
400
- }
401
- const safeObservedSessionTabTarget = observedSessionTabTarget;
402
- let currentSessionTabTarget = safeObservedSessionTabTarget;
403
- if (!currentSessionTabTarget && nestedBatchClose === undefined && !unobservedMutation) {
404
- // Window/diff responses do not report the final URL; URL2 is intent, not redirect evidence.
405
- currentSessionTabTarget = resultingPageState.pageTargetMayHaveChanged
406
- ? succeeded && !destinationTransition ? normalizeSessionTabTarget({ url: resultingPageState.currentPageUrl }) : undefined
407
- : deriveSessionTabTarget({ command: directClose ? "close" : prepared.executionPlan.commandInfo.command, data: pageTargetData, navigationSummary, previousTarget: prepared.priorSessionTabTarget, subcommand: prepared.executionPlan.commandInfo.subcommand });
408
- }
409
- let aboutBlankSessionMismatch;
410
- let electronPostCommandHealth;
411
- let electronRefFreshnessDiagnostic;
412
- let electronSessionMismatch;
413
- let electronStatusAfterCommand;
414
- const explicitlyTargetsAboutBlank = dispatchedCommands.some((step) => commandExplicitlyTargetsAboutBlank(extractUpstreamCommandTokens(step)));
415
- const shouldTreatAboutBlankAsMismatch = succeeded && !tabTransition && !destinationTransition && !explicitlyTargetsAboutBlank && nestedBatchClose === undefined && prepared.priorSessionTabTarget !== undefined && !isAboutBlankSessionTabTarget(prepared.priorSessionTabTarget) && isAboutBlankSessionTabTarget(observedSessionTabTarget ?? currentSessionTabTarget);
416
- let sessionTabCorrection = prepared.sessionTabCorrection;
417
- if (shouldTreatAboutBlankAsMismatch && prepared.priorSessionTabTarget) {
418
- const aboutBlankObservedTarget = observedSessionTabTarget ?? currentSessionTabTarget;
419
- const aboutBlankRecovery = await collectSessionTabSelection({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, target: prepared.priorSessionTabTarget });
420
- const appliedAboutBlankRecovery = aboutBlankRecovery ? await applyOpenResultTabCorrection({ correction: aboutBlankRecovery, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
421
- if (appliedAboutBlankRecovery) {
422
- sessionTabCorrection = appliedAboutBlankRecovery;
423
- currentSessionTabTarget = prepared.priorSessionTabTarget;
424
- }
425
- else
426
- currentSessionTabTarget = aboutBlankObservedTarget ?? normalizeSessionTabTarget({ url: "about:blank" });
427
- aboutBlankSessionMismatch = { activeUrl: "about:blank", recoveryApplied: appliedAboutBlankRecovery !== undefined, recoveryHint: buildAboutBlankRecoveryHint(), targetTitle: prepared.priorSessionTabTarget.title, targetUrl: prepared.priorSessionTabTarget.url };
428
- const electronRecord = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords, prepared.executionPlan.namespace);
429
- if (electronRecord && prepared.executionPlan.sessionName) {
430
- electronStatusAfterCommand = await inspectElectronLaunchStatus(electronRecord);
431
- electronSessionMismatch = buildElectronSessionMismatch({ managedSession: { sessionName: prepared.executionPlan.sessionName, title: aboutBlankObservedTarget?.title, url: aboutBlankObservedTarget?.url ?? "about:blank" }, record: electronRecord, statusTargets: electronStatusAfterCommand.targets });
432
- }
433
- }
434
- if (succeeded && prepared.priorSessionTabTarget && !sessionTabCorrection && !aboutBlankSessionMismatch && !commandExplicitlyTargetsAboutBlank(prepared.commandTokens) && observedSessionTabTarget && shouldCorrectSessionTabAfterCommand({ command: prepared.executionPlan.commandInfo.command, pinningRequired: prepared.sessionTabPinningReason !== undefined, sessionName: prepared.executionPlan.sessionName })) {
435
- const postCommandTabCorrection = await collectSessionTabSelection({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, target: observedSessionTabTarget });
436
- if (postCommandTabCorrection) {
437
- const appliedPostCommandCorrection = await applyOpenResultTabCorrection({ correction: postCommandTabCorrection, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal });
438
- if (appliedPostCommandCorrection && !sessionTabCorrection)
439
- sessionTabCorrection = appliedPostCommandCorrection;
440
- }
441
- }
442
- const electronRecordForCommand = findElectronLaunchRecordForSession(prepared.executionPlan.sessionName, electronLaunchRecords, prepared.executionPlan.namespace);
443
- if (succeeded && electronRecordForCommand && shouldInspectElectronPostCommandHealth(prepared.executionPlan.commandInfo.command)) {
444
- electronStatusAfterCommand ??= await inspectElectronLaunchStatus(electronRecordForCommand);
445
- electronPostCommandHealth = buildElectronPostCommandHealthDiagnostic({ command: prepared.executionPlan.commandInfo.command, record: electronRecordForCommand, status: electronStatusAfterCommand, target: observedSessionTabTarget ?? currentSessionTabTarget });
446
- if (electronPostCommandHealth && electronPostCommandHealth.reason !== "process-dead") {
447
- await sleepMs(electronPostCommandStatusSettleMs);
448
- electronStatusAfterCommand = await inspectElectronLaunchStatus(electronRecordForCommand);
449
- electronPostCommandHealth = buildElectronPostCommandHealthDiagnostic({ command: prepared.executionPlan.commandInfo.command, record: electronRecordForCommand, status: electronStatusAfterCommand, target: observedSessionTabTarget ?? currentSessionTabTarget });
450
- }
451
- if (electronPostCommandHealth)
452
- succeeded = false;
453
- }
454
- let fillVerificationDiagnostic;
455
- let selectorTextVisibilityDiagnostics = [];
456
- let electronBroadGetTextScopeDiagnostics = [];
457
- const timeoutPartialProgress = processResult.timedOut && !recordingStopRecovery && !prepared.readConfirmation ? await collectTimeoutPartialProgress({ commandTokens: prepared.commandTokens, compiledJob: prepared.compiledJob, cwd, operationCwd: input.operationCwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, stdin: prepared.runtimeToolStdin }) : undefined;
458
- if (!currentSessionTabTarget && timeoutPartialProgress?.liveUrlRecovered === true) {
459
- currentSessionTabTarget = normalizeSessionTabTarget(timeoutPartialProgress.currentPage);
460
- }
461
- if (succeeded) {
462
- const fillRefSnapshot = prepared.resolvedSemanticActionRefSnapshot ?? prepared.priorRefSnapshotState;
463
- fillVerificationDiagnostic = await collectFillVerificationDiagnostic({ commandTokens: prepared.commandTokens, cwd, forceValueVerification: electronRecordForCommand !== undefined, namespace: prepared.executionPlan.namespace, refSnapshot: fillRefSnapshot, sessionName: prepared.executionPlan.sessionName, signal });
464
- }
465
- if (succeeded && electronRecordForCommand) {
466
- electronRefFreshnessDiagnostic = buildElectronRefFreshnessDiagnostic({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, record: electronRecordForCommand, sessionName: prepared.executionPlan.sessionName, stdin: prepared.runtimeToolStdin });
467
- }
468
- if (succeeded && prepared.executionPlan.commandInfo.command === "snapshot") {
469
- overlayBlockerDiagnostic = collectSnapshotOverlayBlockerDiagnostic(presentationEnvelope?.data);
470
- }
471
- if (succeeded && !overlayBlockerDiagnostic && !sessionTabCorrection && !aboutBlankSessionMismatch && !electronRecordForCommand && !clickDispatchDiagnostic)
472
- overlayBlockerDiagnostic = await collectOverlayBlockerDiagnostic({ command: prepared.executionPlan.commandInfo.command, cwd, data: presentationEnvelope?.data, namespace: prepared.executionPlan.namespace, navigationSummary, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName, signal });
473
- if (succeeded) {
474
- selectorTextVisibilityDiagnostics = await collectSelectorTextVisibilityDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, cwd, data: presentationEnvelope?.data, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal });
475
- if (electronRecordForCommand)
476
- electronBroadGetTextScopeDiagnostics = collectElectronBroadGetTextScopeDiagnostics({ commandInfo: prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens, currentTarget: currentSessionTabTarget, data: presentationEnvelope?.data, electronLaunchRecords, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName });
477
- }
478
- const activeNetworkRoutes = sessionStateKey ? networkRoutesBySession.get(sessionStateKey) : undefined;
479
- const networkRouteDiagnostics = succeeded && prepared.executionPlan.commandInfo.command === "network" && prepared.executionPlan.commandInfo.subcommand === "requests" && prepared.executionPlan.sessionName
480
- ? buildNetworkRouteDiagnostics(presentationEnvelope?.data, activeNetworkRoutes)
481
- : undefined;
482
- networkRoutesBySession = applyNetworkRouteState({ commandTokens: prepared.commandTokens, routesBySession: networkRoutesBySession, sessionName: sessionStateKey, succeeded });
483
- const comboboxFocusDiagnostic = succeeded ? await collectComboboxFocusDiagnostic({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, cwd, namespace: prepared.executionPlan.namespace, semanticAction: prepared.compiledSemanticAction, sessionName: prepared.executionPlan.sessionName, signal }) : undefined;
484
- const recordingDependencyWarning = await collectRecordingDependencyWarning({ command: prepared.executionPlan.commandInfo.command, commandTokens: prepared.commandTokens, succeeded });
485
- const scrollNoopDiagnostic = succeeded && prepared.shouldProbeScrollNoop ? buildScrollNoopDiagnostic(prepared.scrollPositionBefore, await collectScrollPositionSnapshot({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal })) : undefined;
486
- const batchRefSnapshotState = prepared.executionPlan.commandInfo.command === "batch" ? extractLatestRefSnapshotStateFromBatchResults(Array.isArray(presentationEnvelope?.data) ? presentationEnvelope.data.map((row, index) => {
487
- const snapshot = confirmedEffects.find(effect => effect.index === index && effect.command === "snapshot");
488
- return snapshot && isRecord(row) ? { ...row, command: ["snapshot"], result: snapshot.data, success: snapshot.succeeded } : row;
489
- }) : presentationEnvelope?.data) : undefined;
490
- let currentRefSnapshot;
491
- let currentRefSnapshotInvalidation;
492
- if (sessionStateKey && !browserIndependentRead) {
493
- const sessionClosed = (directClose && succeeded) || nestedBatchClosed;
494
- if (sessionClosed) {
495
- state.attachedSessionKeys.delete(sessionStateKey);
496
- networkRoutesBySession = new Map(networkRoutesBySession);
497
- networkRoutesBySession.delete(sessionStateKey);
498
- sessionPageState.clearSession(sessionStateKey);
499
- state.closedManagedSessionNames.add(sessionStateKey);
500
- }
501
- else {
502
- // A batch that times out or returns unparseable output yields no result rows, but the daemon
503
- // may already have executed a recording swap or page-provided WebMCP tool; fall back to the
504
- // planned steps then. This can over-invalidate by one snapshot, but never under-invalidates.
505
- const directTransitionInvalidation = getCommandRefSnapshotInvalidation(prepared.commandTokens);
506
- const plannedBatchTransitionInvalidation = !Array.isArray(presentationEnvelope?.data)
507
- ? batchCommandSteps.map(getCommandRefSnapshotInvalidation).find((invalidation) => invalidation !== undefined)
508
- : undefined;
509
- const pageTransitionInvalidation = unobservedMutation && !failedTransitionReverification
510
- ? buildPageTransitionRefSnapshotInvalidation("A dispatched mutation was interrupted without a final outcome. Verify the current URL and take a fresh snapshot before deciding whether to retry.")
511
- : unsettledWebMcpMutation
512
- ? buildPageTransitionRefSnapshotInvalidation("A detached WebMCP invocation is still pending or failed to settle and can mutate, rerender, or navigate the page, so prior snapshot refs remain invalid after URL verification. Run webmcp result or cancel, then take a fresh snapshot before using page-scoped refs.")
513
- : processResult.agentBrowserStarted && nativeCommandMayHaveExecuted && (directTransitionInvalidation || plannedBatchTransitionInvalidation)
514
- ? directTransitionInvalidation ?? plannedBatchTransitionInvalidation
515
- : failedTransitionReverification
516
- ? buildPageTransitionRefSnapshotInvalidation("A failed page transition may still have changed the page, so the prior snapshot refs were invalidated. Run snapshot -i before using page-scoped refs.")
517
- : batchRefSnapshotState?.invalidation?.reason === "page-transition"
518
- ? batchRefSnapshotState.invalidation
519
- : undefined;
520
- if (currentSessionTabTarget) {
521
- const tabUpdate = sessionPageState.applyTabTarget({ sessionName: sessionStateKey, target: currentSessionTabTarget, update: sessionPageStateUpdate });
522
- if (!tabUpdate.applied && succeeded)
523
- sessionPageState.markPinning(sessionStateKey, "drift");
524
- }
525
- else if (processResult.agentBrowserStarted && (unobservedMutation || resultingPageState.pageUrlUnknown || resultingPageState.pageTargetMayHaveChanged) && !(prepared.commandTokens[0] === "session" && prepared.commandTokens[1] === "info")) {
526
- sessionPageState.markTabTargetUnknown({ sessionName: sessionStateKey, update: sessionPageStateUpdate });
527
- }
528
- let refSnapshot = unsettledWebMcpMutation || unobservedMutation
529
- ? undefined
530
- : prepared.executionPlan.commandInfo.command === "batch"
531
- ? batchRefSnapshotState?.snapshot
532
- : succeeded
533
- ? prepared.executionPlan.commandInfo.command === "snapshot" || confirmedCommand === "snapshot" ? extractRefSnapshotFromData(confirmedData ?? presentationEnvelope?.data) : prepared.resolvedSemanticActionRefSnapshot ?? overlayBlockerDiagnostic?.snapshot
534
- : undefined;
535
- const refreshArgs = batchRefSnapshotState?.refreshArgs ?? (succeeded && prepared.commandTokens[0] === "snapshot" && isRecord(presentationEnvelope?.data) && isRecord(presentationEnvelope.data.snapshot) && !refSnapshot
536
- ? prepared.commandTokens.filter((token) => token !== "--delta" && token !== "--full") : undefined);
537
- // Native owns delta baselines. Read complete refs without advancing that baseline
538
- // rather than maintaining a second revision/tree cache in the wrapper.
539
- if (refreshArgs && readConfirmation?.state !== "pending" && !unsettledWebMcpMutation && !unobservedMutation) {
540
- refSnapshot = extractRefSnapshotFromData(await runSessionCommandData({ args: refreshArgs, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal }));
541
- if (!refSnapshot)
542
- sessionPageState.applyRefSnapshotInvalidation({ invalidation: buildPageTransitionRefSnapshotInvalidation("The native snapshot delta did not include complete refs and the full ref read failed. Run snapshot -i before using refs."), sessionName: sessionStateKey, update: sessionPageStateUpdate });
543
- }
544
- if (refSnapshot) {
545
- const refUpdate = sessionPageState.applyRefSnapshot({ fallbackTarget: currentSessionTabTarget, sessionName: sessionStateKey, snapshot: refSnapshot, update: sessionPageStateUpdate });
546
- currentRefSnapshot = refUpdate.refSnapshot;
547
- currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
548
- }
549
- else if (pageTransitionInvalidation) {
550
- const refUpdate = sessionPageState.applyRefSnapshotInvalidation({ invalidation: pageTransitionInvalidation, sessionName: sessionStateKey, update: sessionPageStateUpdate });
551
- currentRefSnapshot = refUpdate.refSnapshot;
552
- currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
553
- }
554
- else {
555
- const stateView = sessionPageState.get(sessionStateKey);
556
- currentRefSnapshot = stateView.refSnapshot;
557
- currentRefSnapshotInvalidation = stateView.refSnapshotInvalidation;
558
- }
559
- }
560
- }
561
- const priorManagedSessionActive = managedSessionActive;
562
- const priorManagedSessionCwd = managedSessionCwd;
563
- const priorManagedSessionHeadedAutosaveInterval = managedSessionHeadedAutosaveInterval;
564
- const priorManagedSessionName = managedSessionName;
565
- const priorManagedSessionNamespace = managedSessionNamespace;
566
- const priorManagedSessionKey = getSessionContextKey(priorManagedSessionName, priorManagedSessionNamespace) ?? priorManagedSessionName;
567
- const closeAllTargetsPriorManagedSession = closeAllApplied
568
- && priorManagedSessionActive
569
- && isAgentBrowserSessionIdentityKeyInNamespace(priorManagedSessionKey, prepared.executionPlan.namespace);
570
- const closeAllRetainsPriorManagedSession = closeAllTargetsPriorManagedSession
571
- && nestedBatchRemainsActive
572
- && sessionStateKey === priorManagedSessionKey;
573
- const closeAllClosesPriorManagedSession = closeAllTargetsPriorManagedSession && !closeAllRetainsPriorManagedSession;
574
- const commandClosesSession = directClose || nestedBatchClosed || closeAllClosesPriorManagedSession;
575
- const closeCommandSucceeded = (directClose && succeeded) || nestedBatchClosed || closeAllClosesPriorManagedSession;
576
- const closeTargetsPriorManagedNamespace = prepared.executionPlan.namespace === priorManagedSessionNamespace;
577
- const managedCloseSessionName = closeAllClosesPriorManagedSession
578
- ? priorManagedSessionName
579
- : closeCommandSucceeded && prepared.executionPlan.sessionName === priorManagedSessionName && closeTargetsPriorManagedNamespace
580
- ? prepared.executionPlan.sessionName
581
- : prepared.executionPlan.managedSessionName;
582
- const postLaunchBatchFailure = !succeeded && processSucceeded && parseSucceeded && prepared.sessionMode === "fresh" && prepared.executionPlan.commandInfo.command === "batch" && batchStartedManagedBrowser(presentationEnvelope?.data);
583
- const postLaunchTimeoutWithPage = !succeeded && processResult.timedOut && prepared.sessionMode === "fresh" && prepared.executionPlan.commandInfo.command === "batch" && timeoutPartialProgress?.liveUrlRecovered === true;
584
- const failedFreshSessionMayHaveStarted = !succeeded
585
- && (processResult.agentBrowserStarted || (!processResult.aborted && processResult.spawnError === undefined))
586
- && prepared.sessionMode === "fresh"
587
- && prepared.executionPlan.managedSessionName === prepared.executionPlan.sessionName;
588
- const failedFreshDaemon = failedFreshSessionMayHaveStarted && prepared.executionPlan.sessionName
589
- ? await inspectManagedSessionDaemon({
590
- cwd,
591
- headedManagedAutosaveInterval: prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval,
592
- namespace: prepared.executionPlan.namespace,
593
- sessionName: prepared.executionPlan.sessionName,
594
- timeoutMs: Math.min(implicitSessionCloseTimeoutMs, 2_000),
595
- })
596
- : undefined;
597
- if (failedFreshDaemon?.status === "active") {
598
- state.managedSessionRestoreState.recordDaemonRestoreKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace, failedFreshDaemon.restoreKey);
599
- }
600
- // Only a confirmed inactive daemon proves that a started fresh command did not establish browser ownership.
601
- const postLaunchFreshFailure = failedFreshDaemon !== undefined && failedFreshDaemon.status !== "inactive";
602
- const managedTransitionSucceeded = succeeded || nestedBatchClosed || nestedBatchRemainsActive || postLaunchBatchFailure || postLaunchTimeoutWithPage || postLaunchFreshFailure;
603
- const managedSessionState = resolveManagedSessionState({ command: commandClosesSession ? "close" : prepared.executionPlan.commandInfo.command, managedSessionName: managedCloseSessionName, managedSessionNamespace: prepared.executionPlan.namespace, priorActive: priorManagedSessionActive, priorNamespace: priorManagedSessionNamespace, priorSessionName: priorManagedSessionName, succeeded: managedTransitionSucceeded });
604
- if (!managedTransitionSucceeded && prepared.sessionMode === "fresh" && prepared.executionPlan.managedSessionName) {
605
- state.managedSessionRestoreState.clear(prepared.executionPlan.managedSessionName, prepared.executionPlan.namespace);
606
- }
607
- const replacedManagedSessionName = managedSessionState.replacedSessionName;
608
- managedSessionActive = managedSessionState.active;
609
- managedSessionName = managedSessionState.sessionName;
610
- managedSessionNamespace = managedSessionState.namespace;
611
- const executionTargetsManagedSession = prepared.executionPlan.sessionName
612
- && getAgentBrowserSessionIdentityKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace)
613
- === getAgentBrowserSessionIdentityKey(managedSessionName, managedSessionNamespace);
614
- if (!managedSessionActive) {
615
- managedSessionCompatibilityWorkaround = undefined;
616
- managedSessionHeadedAutosaveDisabled = false;
617
- managedSessionHeadedAutosaveInterval = undefined;
618
- }
619
- else if (managedTransitionSucceeded && executionTargetsManagedSession && prepared.ownedManagedSessionContext && !prepared.ownedManagedSessionContext.reuseOnly) {
620
- managedSessionCompatibilityWorkaround = prepared.compatibilityWorkaround;
621
- managedSessionHeadedAutosaveDisabled = prepared.ownedManagedSessionContext?.headedManagedAutosaveDisabled === true;
622
- managedSessionHeadedAutosaveInterval = prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval;
623
- }
624
- if (closeCommandSucceeded && managedCloseSessionName === priorManagedSessionName && !managedSessionActive) {
625
- const daemonRestoreKey = state.managedSessionRestoreState.getDaemonRestoreKey(managedCloseSessionName, priorManagedSessionNamespace);
626
- const ownedRestoreKey = !state.managedSessionRestoreState.isDisabled(managedCloseSessionName, priorManagedSessionNamespace)
627
- && isManagedSessionRestoreKey(daemonRestoreKey) ? daemonRestoreKey : null;
628
- state.managedSessionRestoreState.clear(managedCloseSessionName, priorManagedSessionNamespace);
629
- pruneOwnedManagedSessionRestoreSnapshots({
630
- cwd,
631
- namespace: priorManagedSessionNamespace,
632
- restoreKey: ownedRestoreKey,
633
- statePath: rawCloseStatePath,
634
- });
635
- freshSessionOrdinal += 1;
636
- managedSessionName = createFreshSessionName(state.managedSessionBaseName, state.ephemeralSessionSeed, freshSessionOrdinal);
637
- managedSessionNamespace = undefined;
638
- }
639
- let managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: managedSessionActive, activeBefore: priorManagedSessionActive, attemptedSessionName: managedCloseSessionName, command: commandClosesSession ? "close" : prepared.executionPlan.commandInfo.command, currentSessionName: managedSessionName, currentSessionNamespace: managedSessionNamespace, previousSessionName: priorManagedSessionName, replacedSessionName: replacedManagedSessionName, replacedSessionNamespace: priorManagedSessionNamespace, sessionMode: prepared.sessionMode, succeeded: managedTransitionSucceeded });
640
- if (prepared.executionPlan.managedSessionName && managedTransitionSucceeded && managedSessionActive) {
641
- if (!priorManagedSessionActive || replacedManagedSessionName)
642
- managedSessionCwd = cwd;
643
- managedSessionNamespace = prepared.executionPlan.namespace;
644
- }
645
- if (sessionStateKey && succeeded) {
646
- if (openResultTabCorrection || sessionTabCorrection || aboutBlankSessionMismatch?.recoveryApplied)
647
- sessionPageState.markPinning(sessionStateKey, "drift");
648
- else if (prepared.sessionTabPinningReason === "restore" && observedSessionTabTarget)
649
- sessionPageState.clearRestorePinning(sessionStateKey);
650
- }
651
- if (replacedManagedSessionName) {
652
- const replacedSessionStateKey = getSessionContextKey(replacedManagedSessionName, priorManagedSessionNamespace);
653
- const replacedSessionKey = replacedSessionStateKey ?? replacedManagedSessionName;
654
- const replacedCloseError = await closeManagedSession({ confirmActions: sessionPageState.get(replacedSessionKey).confirmActions ?? process.env.AGENT_BROWSER_CONFIRM_ACTIONS, cwd: priorManagedSessionCwd, headedManagedAutosaveInterval: priorManagedSessionHeadedAutosaveInterval, namespace: priorManagedSessionNamespace, preserveAttachedBrowserSession: state.attachedSessionKeys.has(replacedSessionKey), restoreState: state.managedSessionRestoreState, sessionName: replacedManagedSessionName, socketDir: state.ownedManagedSessions.get(replacedSessionKey)?.socketDir, timeoutMs: implicitSessionCloseTimeoutMs });
655
- if (managedSessionOutcome) {
656
- managedSessionOutcome = {
657
- ...managedSessionOutcome,
658
- replacedSessionClosed: !replacedCloseError,
659
- summary: replacedCloseError
660
- ? `${managedSessionOutcome.summary} Previous session ${replacedManagedSessionName} remains wrapper-owned because automatic close failed; retry an explicit close.`
661
- : managedSessionOutcome.summary,
662
- };
663
- }
664
- if (!replacedCloseError) {
665
- networkRoutesBySession = new Map(networkRoutesBySession);
666
- networkRoutesBySession.delete(replacedSessionKey);
667
- sessionPageState.clearSession(replacedSessionKey);
668
- state.attachedSessionKeys.delete(replacedSessionKey);
669
- state.closedManagedSessionNames.add(replacedSessionKey);
670
- }
671
- }
672
- let electronLaunchRecord;
673
- let electronFailedConnectCleanup = prepared.electronFailedConnectCleanup;
674
- let electronHandoff = prepared.electronHandoff;
675
- if (prepared.electronLaunch) {
676
- if (succeeded && prepared.executionPlan.sessionName) {
677
- const electronSessionName = prepared.executionPlan.sessionName;
678
- const electronSessionStateKey = sessionStateKey ?? electronSessionName;
679
- electronLaunchRecord = { ...prepared.electronLaunch.record, namespace: prepared.executionPlan.namespace, sessionName: electronSessionName };
680
- const electronHandoffMode = prepared.compiledElectron?.action === "launch" ? prepared.compiledElectron.handoff : "connect";
681
- try {
682
- electronHandoff = await collectElectronHandoff({ cwd, handoff: electronHandoffMode, namespace: prepared.executionPlan.namespace, sessionName: electronSessionName, signal });
683
- }
684
- catch (error) {
685
- electronHandoff = {
686
- error: error instanceof Error ? error.message : String(error),
687
- failureCategory: signal?.aborted ? "aborted" : "upstream-error",
688
- handoff: electronHandoffMode,
689
- };
690
- }
691
- if (electronHandoff.error) {
692
- succeeded = false;
693
- presentationEnvelope = { error: electronHandoff.error, success: false };
694
- const closeError = await closeManagedSession({ confirmActions: sessionPageState.get(electronSessionStateKey).confirmActions ?? process.env.AGENT_BROWSER_CONFIRM_ACTIONS, cwd, headedManagedAutosaveInterval: prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval, namespace: prepared.executionPlan.namespace, policyLock: prepared.managedSessionPolicyLock, preserveAttachedBrowserSession: input.preserveAttachedBrowserSession, restoreState: state.managedSessionRestoreState, sessionName: electronSessionName, timeoutMs: implicitSessionCloseTimeoutMs });
695
- electronFailedConnectCleanup = await cleanupElectronLaunchResources({ child: prepared.electronLaunch.child, record: electronLaunchRecord, timeoutMs: implicitSessionCloseTimeoutMs });
696
- electronLaunchRecord = electronFailedConnectCleanup.record;
697
- if (electronFailedConnectCleanup.partial) {
698
- electronLaunchRecords.set(electronLaunchRecord.launchId, electronLaunchRecord);
699
- electronChildProcesses.set(electronLaunchRecord.launchId, prepared.electronLaunch.child);
700
- }
701
- else {
702
- electronLaunchRecords.delete(electronLaunchRecord.launchId);
703
- electronChildProcesses.delete(electronLaunchRecord.launchId);
704
- }
705
- if (!closeError) {
706
- state.closedManagedSessionNames.add(electronSessionStateKey);
707
- networkRoutesBySession = new Map(networkRoutesBySession);
708
- networkRoutesBySession.delete(electronSessionStateKey);
709
- sessionPageState.clearSession(electronSessionStateKey);
710
- if (managedSessionName === electronSessionName && managedSessionNamespace === prepared.executionPlan.namespace) {
711
- managedSessionActive = false;
712
- freshSessionOrdinal += 1;
713
- managedSessionName = createFreshSessionName(state.managedSessionBaseName, state.ephemeralSessionSeed, freshSessionOrdinal);
714
- managedSessionNamespace = undefined;
715
- }
716
- }
717
- managedSessionOutcome = buildManagedSessionOutcome({ activeAfter: managedSessionActive, activeBefore: priorManagedSessionActive, attemptedSessionName: electronSessionName, command: prepared.executionPlan.commandInfo.command, currentSessionName: managedSessionName, currentSessionNamespace: managedSessionNamespace, previousSessionName: priorManagedSessionName, replacedSessionName: replacedManagedSessionName, replacedSessionNamespace: priorManagedSessionNamespace, sessionMode: prepared.sessionMode, succeeded: false });
718
- }
719
- else {
720
- electronLaunchRecords.set(electronLaunchRecord.launchId, electronLaunchRecord);
721
- electronChildProcesses.set(electronLaunchRecord.launchId, prepared.electronLaunch.child);
722
- if (electronHandoff.refSnapshot) {
723
- const refUpdate = sessionPageState.applyRefSnapshot({ sessionName: electronSessionStateKey, snapshot: electronHandoff.refSnapshot, update: sessionPageStateUpdate });
724
- currentRefSnapshot = refUpdate.refSnapshot;
725
- currentRefSnapshotInvalidation = refUpdate.refSnapshotInvalidation;
726
- if (electronHandoff.refSnapshot.target) {
727
- const targetUpdate = sessionPageState.applyTabTarget({ sessionName: electronSessionStateKey, target: electronHandoff.refSnapshot.target, update: sessionPageStateUpdate });
728
- currentSessionTabTarget = targetUpdate.tabTarget;
729
- }
730
- }
731
- }
732
- }
733
- else {
734
- electronFailedConnectCleanup = await cleanupElectronLaunchResources({ child: prepared.electronLaunch.child, record: prepared.electronLaunch.record, timeoutMs: implicitSessionCloseTimeoutMs });
735
- electronLaunchRecord = electronFailedConnectCleanup.record;
736
- }
737
- }
738
- let errorText = recordingStopRecovery?.recovery.healed ? undefined : getAgentBrowserErrorText({ aborted: processResult.aborted, command: prepared.executionPlan.commandInfo.command, effectiveArgs: prepared.redactedProcessArgs, envelope: presentationEnvelope, exitCode: processResult.exitCode, parseError, plainTextInspection, staleRefArgs: getStaleRefArgs(prepared.commandTokens, prepared.runtimeToolStdin), spawnError: processResult.spawnError, stderr: processResult.stderr, timedOut: processResult.timedOut, timeoutMs: processResult.timeoutMs, wrapperRecoveryHint: buildWrapperRecoveryHint({ sessionTabCorrection }) });
739
- if (errorText && presentationEnvelope?.success === false && extractEnvelopeErrorText(presentationEnvelope.error) === undefined)
740
- presentationEnvelope = { ...presentationEnvelope, error: errorText };
741
- if (errorText) {
742
- const clipboardWritePayloadCandidates = getClipboardWritePayloadCandidates(prepared.commandTokens);
743
- errorText = redactClipboardPermissionEcho(prepared.executionPlan.commandInfo, errorText);
744
- if (presentationEnvelope?.error !== undefined)
745
- presentationEnvelope = { ...presentationEnvelope, error: redactClipboardPermissionErrorValue(prepared.executionPlan.commandInfo, presentationEnvelope.error, clipboardWritePayloadCandidates) };
746
- }
747
- if ((plainTextUpgrade || textOutput) && errorText)
748
- presentationEnvelope = { ...presentationEnvelope, success: false, error: errorText };
749
- const resultRetainsPreparedManagedSession = !managedSessionOutcome || (managedSessionOutcome.activeAfter
750
- && managedSessionOutcome.attemptedSessionName === managedSessionOutcome.currentSessionName);
751
- const resultHeadedManagedAutosaveDisabled = prepared.ownedManagedSessionContext?.headedManagedAutosaveDisabled === true
752
- && resultRetainsPreparedManagedSession
753
- && !(commandClosesSession && succeeded);
754
- const resultHeadedManagedAutosaveInterval = resultRetainsPreparedManagedSession && !(commandClosesSession && succeeded)
755
- ? prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval
756
- : undefined;
757
- // Commit native lifecycle facts to the execution state before rendering/export can fail.
758
- const finalHelperConfirmation = parseReadConfirmation(state.observedBrowserEffects?.readConfirmation);
759
- if (finalHelperConfirmation?.state === "pending") {
760
- confirmationFromHelper ||= state.observedBrowserEffects?.readConfirmation !== readConfirmationEvent;
761
- readConfirmationEvent = finalHelperConfirmation;
762
- succeeded = false;
763
- }
764
- applyBrowserRunStatePatch(state, { artifactManifest, freshSessionOrdinal, managedSessionActive, managedSessionCompatibilityWorkaround, managedSessionHeadedAutosaveDisabled, managedSessionHeadedAutosaveInterval, managedSessionCwd, managedSessionName, managedSessionNamespace, networkRoutesBySession });
765
- state.observedBrowserEffects = {
766
- args: prepared.redactedArgs, command: directClose ? "close" : prepared.executionPlan.commandInfo.command, subcommand: directClose ? undefined : prepared.executionPlan.commandInfo.subcommand,
767
- sessionName: prepared.executionPlan.sessionName, namespace: prepared.executionPlan.namespace, sessionMode: prepared.sessionMode,
768
- usedImplicitSession: prepared.executionPlan.usedImplicitSession, agentBrowserStarted: processResult.agentBrowserStarted,
769
- nativeSucceeded: succeeded, managedSessionOutcome, managedSessionCwd: prepared.ownedManagedSessionContext?.cwd ?? managedSessionCwd, compatibilityWorkaround: prepared.compatibilityWorkaround,
770
- managedSessionHeadedAutosaveDisabled: resultHeadedManagedAutosaveDisabled, managedSessionHeadedAutosaveInterval: resultHeadedManagedAutosaveInterval,
771
- managedSessionRestoreDisabled: state.managedSessionRestoreState.isDisabled(prepared.executionPlan.sessionName, prepared.executionPlan.namespace),
772
- closeAllApplied, readConfirmation: readConfirmationEvent ?? prepared.readConfirmation ?? state.observedBrowserEffects?.readConfirmation,
773
- electron: electronLaunchRecord ? { launch: electronLaunchRecord, cleanup: electronFailedConnectCleanup } : undefined,
774
- batchSteps: Array.isArray(presentationEnvelope?.data) ? presentationEnvelope.data.filter(isRecord).map(row => ({
775
- command: Array.isArray(row.command) && row.command.every(token => typeof token === "string") ? isSuccessfulNativeConfirmedClose(row.command, row.result) ? ["close"] : redactInvocationArgs(row.command) : undefined,
776
- success: row.success === true && !detectConfirmationRequired(row.result), lifecycle: extractAgentBrowserLifecycle(row.result),
777
- })) : undefined,
778
- };
779
- let presentation = plainTextInspection ? { artifacts: undefined, batchFailure: undefined, batchSteps: undefined, content: [{ type: "text", text: inspectionText ?? "" }], data: undefined, fullOutputPath: undefined, fullOutputPaths: undefined, imagePath: undefined, imagePaths: undefined, savedFile: undefined, savedFilePath: undefined, summary: `${prepared.redactedArgs.join(" ")} completed` } : recordingStopRecovery && !recordingStopRecovery.batch ? recordingStopRecovery.presentation : await buildToolPresentation({ textOutput, stdin: prepared.processStdin, modelVisible: input.modelVisible, args: prepared.redactedProcessArgs, artifactManifest, artifactMaxUpdatedAtMs: Date.now(), artifactMinUpdatedAtMs: input.artifactRunStartedAtMs, artifactRequest: screenshotArtifactRequest, batchArtifactRequests: batchScreenshotArtifactRequests, commandInfo: { ...prepared.executionPlan.commandInfo, commandTokens: prepared.commandTokens }, compiledSemanticAction: prepared.compiledSemanticAction, cwd: operationCwd, envelope: presentationEnvelope, errorText, namespace: prepared.executionPlan.namespace, networkRouteDiagnostics, networkRoutes: activeNetworkRoutes, persistentArtifactStore, previousRecordingContactSheetPath: sessionStateKey ? state.activeRecordingReservations?.get(sessionStateKey)?.contactSheetPath : undefined, piCleanupOwnership: sessionStateKey && (state.ownedManagedSessions.has(sessionStateKey) || prepared.executionPlan.managedSessionName !== undefined) ? "wrapper-managed" : "caller-owned", sessionName: prepared.executionPlan.sessionName });
780
- if (recordingStopRecovery)
781
- presentation = mergeRecordingRecoveryPresentation(presentation, recordingStopRecovery);
782
- if (parseError && processResult.exitCode !== 0 && processResult.stderr.trim() && !processResult.timedOut && !processResult.aborted && !processResult.spawnError) {
783
- presentation.failureCategory = "upstream-error";
784
- }
785
- const confirmation = readConfirmationEvent ?? prepared.readConfirmation;
786
- if (confirmation) {
787
- presentation.readConfirmation = confirmation;
788
- if (confirmation.state !== "cleared" || !detectConfirmationRequired(presentationEnvelope?.data)) {
789
- presentation.nextActions = buildReadConfirmationNextActions(confirmation, readConfirmationEvent?.state === "pending");
790
- }
791
- if (readConfirmationEvent?.state === "pending") {
792
- presentation.resultCategory = "failure";
793
- presentation.failureCategory = "confirmation-required";
794
- presentation.successCategory = undefined;
795
- if (confirmationFromHelper)
796
- presentation.content.unshift({ type: "text", text: `Native helper ${confirmation.command ?? "read"} requires confirmation (${confirmation.action ?? "read"}, ${confirmation.id}). The requested command's result, if dispatched, is preserved below.` });
797
- }
798
- }
799
- if (plainTextUpgrade && !textOutput && !succeeded && typeof presentationEnvelope?.data === "string") {
800
- presentation.data = presentationEnvelope.data;
801
- const errorContent = presentation.content[0];
802
- if (errorContent?.type === "text" && presentationEnvelope.data)
803
- errorContent.text += `\n\n${presentationEnvelope.data}`;
804
- if (input.modelVisible !== false)
805
- presentation = await compactLargePresentationOutput({ artifactManifest, commandInfo: prepared.executionPlan.commandInfo, data: presentation.data, persistentArtifactStore, presentation });
806
- }
807
- if (electronHandoff?.error && electronHandoff.failureCategory)
808
- presentation.failureCategory = electronHandoff.failureCategory;
809
- networkRoutesBySession = applyBatchNetworkRouteState({ data: presentationEnvelope?.data, routesBySession: networkRoutesBySession, sessionName: sessionStateKey, succeeded });
810
- if (presentation.resultCategory === "failure" && succeeded) {
811
- succeeded = false;
812
- presentationEnvelope = { ...(presentationEnvelope ?? {}), error: presentation.summary, success: false };
813
- }
814
- if (scrollNoopDiagnostic) {
815
- succeeded = false;
816
- presentation.resultCategory = "failure";
817
- presentation.failureCategory = "upstream-error";
818
- presentationEnvelope = { ...(presentationEnvelope ?? {}), error: "Scroll completed with no observed movement.", success: false };
819
- presentation.summary = "Scroll completed with no observed movement.";
820
- if (isRecord(presentation.data))
821
- presentation.data = { ...presentation.data, noMovement: true, scrolled: false };
822
- if (presentation.content[0]?.type === "text") {
823
- const details = isRecord(presentation.data) ? JSON.stringify(omitUpstreamLifecycle(presentation.data), null, 2) : presentation.content[0].text;
824
- presentation.content[0] = { ...presentation.content[0], text: `Scroll completed with no observed movement.\n\n${details}` };
825
- }
826
- else {
827
- presentation.content.unshift({ type: "text", text: "Scroll completed with no observed movement." });
828
- }
829
- }
830
- if (parseFailureOutput.artifactManifest) {
831
- presentation.artifactManifest = parseFailureOutput.artifactManifest;
832
- presentation.artifactRetentionSummary = parseFailureOutput.artifactRetentionSummary;
833
- }
834
- if (parseFailureOutput.fullOutputPath || parseFailureOutput.fullOutputUnavailable) {
835
- const existingText = presentation.content[0]?.type === "text" ? presentation.content[0].text : "";
836
- const noticeLines = [parseFailureOutput.fullOutputPath ? `Full output path: ${parseFailureOutput.fullOutputPath}` : `Full raw output unavailable: ${parseFailureOutput.fullOutputUnavailable}`, parseFailureOutput.artifactRetentionSummary].filter((item) => item !== undefined);
837
- const notice = noticeLines.join("\n");
838
- presentation.content[0] = { type: "text", text: existingText.length > 0 ? `${existingText}\n\n${notice}` : notice };
839
- }
840
- if (presentation.artifactManifest)
841
- artifactManifest = presentation.artifactManifest;
842
- const qaPreset = prepared.compiledQaPreset
843
- ? (processResult.timedOut ? analyzeQaPresetTimeout(prepared.compiledQaPreset) ?? analyzeQaPresetResults(presentationEnvelope?.data, prepared.compiledQaPreset) : analyzeQaPresetResults(presentationEnvelope?.data, prepared.compiledQaPreset))
844
- : undefined;
845
- if (qaPreset?.passed && presentation.resultCategory === "failure") {
846
- qaPreset.passed = false;
847
- qaPreset.summary = presentation.summary;
848
- qaPreset.failedChecks.push(presentation.summary);
849
- }
850
- let qaAttachedTarget = prepared.compiledQaPreset?.checks.attached
851
- ? await collectQaAttachedTarget({ currentTarget: currentSessionTabTarget ?? prepared.priorSessionTabTarget, cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal })
852
- : undefined;
853
- const sourceLookupElectronContext = prepared.compiledSourceLookup ? getSourceLookupElectronContext({ currentTarget: currentSessionTabTarget, electronLaunchRecords, namespace: prepared.executionPlan.namespace, priorTarget: prepared.priorSessionTabTarget, sessionName: prepared.executionPlan.sessionName }) : undefined;
854
- const sourceLookup = prepared.compiledSourceLookup ? await analyzeSourceLookupResults(presentationEnvelope?.data, prepared.compiledSourceLookup, operationCwd, { electronContext: sourceLookupElectronContext, workspaceRoot: operationCwd }) : undefined;
855
- const networkSourceLookup = prepared.compiledNetworkSourceLookup ? redactNetworkSourceLookupAnalysis(await analyzeNetworkSourceLookupResults(presentationEnvelope?.data, prepared.compiledNetworkSourceLookup, operationCwd)) : undefined;
856
- if (networkSourceLookup && presentation.content[0]?.type === "text")
857
- presentation.content[0] = { ...presentation.content[0], text: `${networkSourceLookup.summary}\n\n${presentation.content[0].text}` };
858
- else if (networkSourceLookup)
859
- presentation.content.unshift({ type: "text", text: networkSourceLookup.summary });
860
- if (sourceLookup && presentation.content[0]?.type === "text")
861
- presentation.content[0] = { ...presentation.content[0], text: `${sourceLookup.summary}\n\n${presentation.content[0].text}` };
862
- else if (sourceLookup)
863
- presentation.content.unshift({ type: "text", text: sourceLookup.summary });
864
- if (qaPreset && !qaPreset.passed && prepared.compiledQaPreset && presentation.failureCategory !== "artifact-missing") {
865
- succeeded = false;
866
- presentation.failureCategory = "qa-failure";
867
- presentation.summary = qaPreset.summary;
868
- const compactText = buildQaCompactFailureText({
869
- causalError: presentation.batchFailure?.failedStep.text,
870
- executedStepCount: presentation.batchSteps?.length,
871
- page: extractQaPageContext({
872
- attachedTarget: qaAttachedTarget,
873
- batchData: presentationEnvelope?.data,
874
- compiled: prepared.compiledQaPreset,
875
- }),
876
- plannedStepCount: prepared.compiledQaPreset.steps.length,
877
- qaPreset,
878
- });
879
- const nonTextContent = presentation.content.filter((item) => item.type !== "text");
880
- presentation.content = [{ type: "text", text: compactText }, ...nonTextContent];
881
- }
882
- else if (qaPreset?.passed && prepared.compiledQaPreset && succeeded) {
883
- const compactText = buildQaCompactPassText({
884
- artifactVerification: presentation.artifactVerification,
885
- batchStepCount: presentation.batchSteps?.length ?? prepared.compiledQaPreset.steps.length,
886
- checks: prepared.compiledQaPreset.checks,
887
- page: extractQaPageContext({
888
- attachedTarget: qaAttachedTarget,
889
- batchData: presentationEnvelope?.data,
890
- compiled: prepared.compiledQaPreset,
891
- }),
892
- qaPreset,
893
- });
894
- presentation.summary = qaPreset.summary;
895
- const nonTextContent = presentation.content.filter((item) => item.type !== "text");
896
- presentation.content = [{ type: "text", text: compactText }, ...nonTextContent];
897
- }
898
- const qaAttachedTargetText = formatQaAttachedTargetText(qaAttachedTarget);
899
- const qaAttachedDiagnosticsText = prepared.compiledQaPreset?.checks.attached && prepared.compiledQaPreset.checks.diagnosticsResetAtStart === false && (prepared.compiledQaPreset.checks.checkNetwork || prepared.compiledQaPreset.checks.checkConsole || prepared.compiledQaPreset.checks.checkErrors)
900
- ? "Attached diagnostics: existing upstream session console/network/error buffers were preserved; rows may include events from before qa.attached started."
901
- : undefined;
902
- const qaAttachedBannerText = [qaAttachedTargetText, qaAttachedDiagnosticsText].filter((part) => typeof part === "string" && part.length > 0).join("\n");
903
- const skipAttachedTargetBanner = qaPreset?.passed && prepared.compiledQaPreset?.checks.attached;
904
- if (!skipAttachedTargetBanner && qaAttachedBannerText && presentation.content[0]?.type === "text")
905
- presentation.content[0] = {
906
- ...presentation.content[0],
907
- text: qaPreset?.passed === false
908
- ? `${presentation.content[0].text}\n\n${qaAttachedBannerText}`
909
- : `${qaAttachedBannerText}\n\n${presentation.content[0].text}`,
910
- };
911
- else if (!skipAttachedTargetBanner && qaAttachedBannerText)
912
- presentation.content.unshift({ type: "text", text: qaAttachedBannerText });
913
- if (managedSessionOutcome && managedSessionOutcome.succeeded !== succeeded)
914
- managedSessionOutcome = { ...managedSessionOutcome, succeeded };
915
- const evalNavigationSummary = navigationSummary ?? extractNavigationSummaryFromData(presentationEnvelope?.data);
916
- const evalSessionTabUrl = sessionStateKey ? sessionPageState.get(sessionStateKey).tabTarget?.url : undefined;
917
- const evalPageUrl = evalNavigationSummary?.url ?? currentSessionTabTarget?.url ?? prepared.priorSessionTabTarget?.url ?? evalSessionTabUrl;
918
- const evalStdinHint = getEvalStdinHint({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, stdin: prepared.runtimeToolStdin });
919
- const evalResultWarning = getEvalResultWarning({ command: prepared.executionPlan.commandInfo.command, data: presentationEnvelope?.data, navigationSummary: evalNavigationSummary, pageUrl: evalPageUrl, stdin: prepared.runtimeToolStdin });
920
- if (readConfirmationEvent)
921
- state.sessionPageState.applyReadConfirmation(readConfirmationEvent, sessionPageStateUpdate);
922
- const resultArtifactManifest = presentation.artifactManifest ?? artifactManifest;
923
- const artifactCleanup = await getArtifactCleanupGuidance({ command: prepared.executionPlan.commandInfo.command, cwd, manifest: resultArtifactManifest, succeeded });
924
- const recordingTransitionReached = prepared.executionPlan.commandInfo.command === "batch"
925
- ? presentation.batchSteps?.some((step) => isRecordPageTransitionCommand(extractUpstreamCommandTokens(step.command ?? [])))
926
- : isRecordPageTransitionCommand(prepared.commandTokens);
927
- const recordingPageWarning = processResult.agentBrowserStarted && !prepared.executionPlan.plainTextInspection && recordingTransitionReached
928
- ? "Page state: this wrapper conservatively invalidates earlier refs after recording starts and URL-bearing restarts. Take a fresh snapshot before continuing; this does not prove the page changed."
929
- : undefined;
930
- const sessionWarning = electronPostCommandHealth ? formatElectronPostCommandHealthText(electronPostCommandHealth) : electronSessionMismatch ? formatElectronSessionMismatchText(electronSessionMismatch) : aboutBlankSessionMismatch ? buildAboutBlankWarning(aboutBlankSessionMismatch) : undefined;
931
- const warningText = [sessionWarning, recordingPageWarning].filter(Boolean).join("\n\n") || undefined;
932
- const redactedContent = input.modelVisible === false ? [] : buildRedactedPresentationContent({ exactSensitiveValues: prepared.exactSensitiveValues, plainTextInspection, presentation, presentationEnvelope, succeeded, userRequestedJson: prepared.userRequestedJson, warningText });
933
- const finalRecoveryState = await prepareFinalResultRecoveryState({ aboutBlankSessionMismatch, batchRefSnapshotState, commandTokens: prepared.commandTokens, compiledSemanticAction: prepared.compiledSemanticAction, currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, cwd, electronPostCommandHealth, errorText, executionPlan: prepared.executionPlan, parseError, plainTextInspection, presentation, processResult, redactedProcessArgs: prepared.redactedProcessArgs, runtimeToolArgs: prepared.runtimeToolArgs, sessionPageState, sessionPageStateUpdate, sessionTabCorrection, signal, succeeded });
934
- currentRefSnapshot = finalRecoveryState.currentRefSnapshot;
935
- currentRefSnapshotInvalidation = finalRecoveryState.currentRefSnapshotInvalidation;
936
- const authoritativePageState = sessionStateKey ? sessionPageState.get(sessionStateKey) : undefined;
937
- const newSnapshot = authoritativePageState?.refSnapshot && authoritativePageState.refSnapshot.snapshotId !== prepared.priorRefSnapshotState?.snapshotId;
938
- const needsDaemonReceipt = prepared.ownedManagedSessionContext && !prepared.ownedManagedSessionContext.reuseOnly && !commandClosesSession && processResult.agentBrowserStarted
939
- && (succeeded || managedSessionOutcome?.activeAfter === true && managedSessionOutcome.currentSessionName === prepared.executionPlan.sessionName)
940
- && !state.managedSessionRestoreState.getDaemonReceipt(prepared.executionPlan.sessionName, prepared.executionPlan.namespace);
941
- if (sessionStateKey && prepared.executionPlan.sessionName && (newSnapshot || needsDaemonReceipt)) {
942
- const daemon = await inspectManagedSessionDaemon({ cwd, namespace: prepared.executionPlan.namespace, sessionName: prepared.executionPlan.sessionName, signal, includeGeneration: true, headedManagedAutosaveInterval: prepared.ownedManagedSessionContext?.headedManagedAutosaveInterval ?? (prepared.ownedManagedSessionContext?.headedManagedAutosaveDisabled ? "0" : undefined), timeoutMs: prepared.processTimeoutMs });
943
- if (newSnapshot) {
944
- sessionPageState.bindSnapshotGeneration(sessionStateKey, daemon.status === "active" ? daemon.generation : undefined);
945
- currentRefSnapshot = sessionPageState.get(sessionStateKey).refSnapshot;
946
- }
947
- if (prepared.ownedManagedSessionContext && daemon.status === "active" && daemon.generation) {
948
- state.managedSessionRestoreState.recordDaemonRestoreKey(prepared.executionPlan.sessionName, prepared.executionPlan.namespace, daemon.restoreKey, daemon.generation);
949
- }
950
- }
951
- if (sessionStateKey && currentRefSnapshot && processSucceeded && parseSucceeded && !unobservedMutation && readConfirmationEvent?.state === "cleared"
952
- && readConfirmationEvent.command === "snapshot" && readConfirmationEvent.action === "snapshot"
953
- && confirmedEffects.some(effect => effect.command === "snapshot" && effect.succeeded
954
- && effect.index === (Array.isArray(presentationEnvelope?.data) ? presentationEnvelope.data.length - 1 : 0) && extractRefSnapshotFromData(effect.data))) {
955
- readConfirmationEvent = { ...readConfirmationEvent, refSnapshotFresh: true };
956
- presentation.readConfirmation = readConfirmationEvent;
957
- sessionPageState.applyReadConfirmation(readConfirmationEvent, sessionPageStateUpdate);
958
- state.observedBrowserEffects = { ...state.observedBrowserEffects, readConfirmation: readConfirmationEvent };
959
- }
960
- if (sessionStateKey)
961
- currentSessionTabTarget = authoritativePageState?.tabTarget;
962
- const currentSessionTabTargetUnknown = authoritativePageState?.tabTargetUnknown === true ? true : undefined;
963
- // ponytail: skip silent ref copies; direct failure receipts need their existing fields until final publication owns those paths.
964
- const result = buildFinalAgentBrowserToolResult({ modelVisible: input.modelVisible, aboutBlankSessionMismatch, artifactCleanup, categoryDetails: finalRecoveryState.categoryDetails, clickDispatchDiagnostic, commandTokens: prepared.commandTokens, comboboxFocusDiagnostic, compiledNetworkSourceLookup: prepared.compiledNetworkSourceLookup, compiledSemanticAction: prepared.compiledSemanticAction, compatibilityWorkaround: prepared.compatibilityWorkaround, currentRefSnapshot: input.modelVisible === false ? undefined : currentRefSnapshot, currentRefSnapshotInvalidation, currentSessionTabTarget, currentSessionTabTargetUnknown, electronBroadGetTextScopeDiagnostics, electronFailedConnectCleanup, electronHandoff, electronLaunch: prepared.electronLaunch, electronLaunchRecord, electronLaunchRecords, electronPostCommandHealth, electronProfileIsolationDetails: input.electronProfileIsolationDetails, electronRefFreshnessDiagnostic, electronSessionMismatch, errorText, evalResultWarning, evalStdinHint, exactSensitiveValues: prepared.exactSensitiveValues, executionPlan: prepared.executionPlan, fillVerificationDiagnostic, headedLaunch: prepared.headedLaunch, inspectionText, preserveAttachedBrowserSession: input.preserveAttachedBrowserSession === true, providerLaunch: prepared.providerLaunch, managedSessionHeadedAutosaveDisabled: !prepared.ownedManagedSessionContext?.reuseOnly && resultHeadedManagedAutosaveDisabled || undefined, managedSessionHeadedAutosaveInterval: prepared.ownedManagedSessionContext?.reuseOnly ? undefined : resultHeadedManagedAutosaveInterval, managedSessionOutcome, managedSessionRestoreDisabled: state.managedSessionRestoreState.isDisabled(prepared.executionPlan.sessionName, prepared.executionPlan.namespace), navigationSummary, networkSourceLookup, noActivePageSnapshotFailure: finalRecoveryState.noActivePageSnapshotFailure, openResultTabCorrection, overlayBlockerDiagnostic, parseError, parseFailureOutput, parseSucceeded, plainTextInspection, presentation, presentationEnvelope, priorSessionTabTarget: prepared.priorSessionTabTarget, processResult, qaAttachedTarget, qaPreset, recordingDependencyWarning, redactedArgs: prepared.redactedArgs, redactedCompiledElectron: prepared.redactedCompiledElectron, redactedCompiledJob: prepared.redactedCompiledJob, redactedCompiledNetworkSourceLookup: prepared.redactedCompiledNetworkSourceLookup, redactedCompiledQaPreset: prepared.redactedCompiledQaPreset, redactedCompiledSemanticAction: prepared.redactedCompiledSemanticAction, redactedCompiledSourceLookup: prepared.redactedCompiledSourceLookup, redactedContent, redactedProcessArgs: prepared.redactedProcessArgs, redactedRecoveryHint: prepared.redactedRecoveryHint, resultArtifactManifest, richInputRecoveryDiagnostic: finalRecoveryState.richInputRecoveryDiagnostic, scrollNoopDiagnostic, selectorTextVisibilityDiagnostics, sessionMode: prepared.sessionMode, sessionTabCorrection, sourceLookup, succeeded, timeoutPartialProgress, unsettledWebMcpMutation, userRequestedJson: prepared.userRequestedJson, visibleRefFallbackDiagnostic: finalRecoveryState.visibleRefFallbackDiagnostic, visibleRefFallbackSessionName: finalRecoveryState.visibleRefFallbackSessionName });
965
- const resultWithCloseAll = closeAllApplied
966
- ? { ...result, details: { ...(isRecord(result.details) ? result.details : {}), closeAllApplied: true } }
967
- : result;
968
- const statePatch = { artifactManifest, freshSessionOrdinal, managedSessionActive, managedSessionCompatibilityWorkaround, managedSessionHeadedAutosaveDisabled, managedSessionHeadedAutosaveInterval, managedSessionCwd, managedSessionName, managedSessionNamespace, networkRoutesBySession };
969
- return { result: resultWithCloseAll, statePatch };
11
+ const native = await observeNativeEffects(input, ownership);
12
+ const page = await observePageEffects(input, native);
13
+ const lifecycle = await commitLifecycleEffects(input, native, page, ownership);
14
+ const { publication, recovery } = await publishOutputEffects(input, native, page, lifecycle);
15
+ return buildOutputResult({ input, native, page, lifecycle, publication }, recovery);
970
16
  }
971
17
  finally {
972
- if (processResult.stdoutSpillPath)
973
- await rm(processResult.stdoutSpillPath, { force: true }).catch(() => undefined);
18
+ const path = input.processResult.stdoutSpillPath;
19
+ if (path !== undefined && path.length > 0) {
20
+ await rm(path, { force: true }).catch(() => {
21
+ // This raw spool is disposable and may already be removed; cleanup must not replace the native outcome or a publication failure.
22
+ });
23
+ }
974
24
  }
975
25
  }