pi-agent-browser-native 0.9.2 → 0.9.4

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