pi-agent-browser-native 0.9.3 → 0.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (394) hide show
  1. package/CHANGELOG.md +106 -5
  2. package/README.md +58 -791
  3. package/dist/extensions/agent-browser/index.js +43101 -2031
  4. package/dist/extensions/agent-browser/lib/argv-descriptor.js +49 -26
  5. package/dist/extensions/agent-browser/lib/argv-grammar.js +82 -93
  6. package/dist/extensions/agent-browser/lib/bash-guard.js +129 -126
  7. package/dist/extensions/agent-browser/lib/batch-lifecycle.js +112 -51
  8. package/dist/extensions/agent-browser/lib/browser-execution-claim-codec.js +61 -0
  9. package/dist/extensions/agent-browser/lib/browser-execution-claim-storage.js +232 -0
  10. package/dist/extensions/agent-browser/lib/browser-execution-claims.js +202 -0
  11. package/dist/extensions/agent-browser/lib/browser-execution-identity.js +77 -0
  12. package/dist/extensions/agent-browser/lib/browser-journal-branch.js +98 -0
  13. package/dist/extensions/agent-browser/lib/browser-journal-contracts.js +1 -0
  14. package/dist/extensions/agent-browser/lib/browser-journal-projection.js +221 -0
  15. package/dist/extensions/agent-browser/lib/browser-journal-reader.js +89 -0
  16. package/dist/extensions/agent-browser/lib/browser-journal-replay.js +246 -0
  17. package/dist/extensions/agent-browser/lib/browser-journal.js +103 -394
  18. package/dist/extensions/agent-browser/lib/browser-legacy-pages.js +220 -0
  19. package/dist/extensions/agent-browser/lib/browser-legacy-projection.js +282 -0
  20. package/dist/extensions/agent-browser/lib/browser-legacy-types.js +1 -0
  21. package/dist/extensions/agent-browser/lib/browser-session-conversion-stream.js +217 -0
  22. package/dist/extensions/agent-browser/lib/browser-session-conversion.js +80 -335
  23. package/dist/extensions/agent-browser/lib/browser-transcript-contracts.js +35 -0
  24. package/dist/extensions/agent-browser/lib/browser-transcript-validation.js +166 -0
  25. package/dist/extensions/agent-browser/lib/browser-transcript.js +137 -82
  26. package/dist/extensions/agent-browser/lib/browser-value-parsing.js +15 -0
  27. package/dist/extensions/agent-browser/lib/command-capabilities.js +340 -0
  28. package/dist/extensions/agent-browser/lib/command-policy.js +107 -88
  29. package/dist/extensions/agent-browser/lib/command-taxonomy.js +49 -322
  30. package/dist/extensions/agent-browser/lib/config-policy.js +138 -343
  31. package/dist/extensions/agent-browser/lib/config-providers.js +71 -0
  32. package/dist/extensions/agent-browser/lib/config-validation.js +231 -0
  33. package/dist/extensions/agent-browser/lib/config.js +20 -8
  34. package/dist/extensions/agent-browser/lib/electron/cdp.js +20 -8
  35. package/dist/extensions/agent-browser/lib/electron/cleanup.js +128 -83
  36. package/dist/extensions/agent-browser/lib/electron/discovery-darwin.js +109 -0
  37. package/dist/extensions/agent-browser/lib/electron/discovery-desktop.js +136 -0
  38. package/dist/extensions/agent-browser/lib/electron/discovery-evidence.js +90 -0
  39. package/dist/extensions/agent-browser/lib/electron/discovery-linux.js +93 -0
  40. package/dist/extensions/agent-browser/lib/electron/discovery-packages.js +162 -0
  41. package/dist/extensions/agent-browser/lib/electron/discovery-types.js +2 -0
  42. package/dist/extensions/agent-browser/lib/electron/discovery.js +140 -549
  43. package/dist/extensions/agent-browser/lib/electron/launch-monitor.js +102 -0
  44. package/dist/extensions/agent-browser/lib/electron/launch-process.js +209 -0
  45. package/dist/extensions/agent-browser/lib/electron/launch-types.js +2 -0
  46. package/dist/extensions/agent-browser/lib/electron/launch.js +261 -355
  47. package/dist/extensions/agent-browser/lib/executable-path.js +21 -12
  48. package/dist/extensions/agent-browser/lib/execution-cwd.js +35 -18
  49. package/dist/extensions/agent-browser/lib/fs-utils.js +1 -9
  50. package/dist/extensions/agent-browser/lib/input-modes/electron.js +162 -121
  51. package/dist/extensions/agent-browser/lib/input-modes/job.js +123 -317
  52. package/dist/extensions/agent-browser/lib/input-modes/lookup-network-evidence.js +116 -0
  53. package/dist/extensions/agent-browser/lib/input-modes/lookup-plan.js +132 -0
  54. package/dist/extensions/agent-browser/lib/input-modes/lookup-redaction.js +57 -0
  55. package/dist/extensions/agent-browser/lib/input-modes/lookup-source-evidence.js +151 -0
  56. package/dist/extensions/agent-browser/lib/input-modes/lookup-workspace.js +142 -0
  57. package/dist/extensions/agent-browser/lib/input-modes/lookups.js +58 -412
  58. package/dist/extensions/agent-browser/lib/input-modes/params.js +86 -40
  59. package/dist/extensions/agent-browser/lib/input-modes/qa-analysis.js +268 -0
  60. package/dist/extensions/agent-browser/lib/input-modes/qa-presentation.js +117 -0
  61. package/dist/extensions/agent-browser/lib/input-modes/script-child.js +396 -0
  62. package/dist/extensions/agent-browser/lib/input-modes/script-protocol.js +86 -0
  63. package/dist/extensions/agent-browser/lib/input-modes/script-types.js +1 -0
  64. package/dist/extensions/agent-browser/lib/input-modes/script-validation.js +60 -0
  65. package/dist/extensions/agent-browser/lib/input-modes/script.js +60 -409
  66. package/dist/extensions/agent-browser/lib/input-modes/semantic-action.js +218 -128
  67. package/dist/extensions/agent-browser/lib/input-modes/shared.js +15 -4
  68. package/dist/extensions/agent-browser/lib/input-modes/types.js +56 -7
  69. package/dist/extensions/agent-browser/lib/json-schema.js +22 -10
  70. package/dist/extensions/agent-browser/lib/launch-scoped-flags.js +17 -5
  71. package/dist/extensions/agent-browser/lib/managed-session-policy-lock.js +92 -425
  72. package/dist/extensions/agent-browser/lib/managed-session-posix-storage.js +58 -0
  73. package/dist/extensions/agent-browser/lib/managed-session-project-identity.js +244 -0
  74. package/dist/extensions/agent-browser/lib/managed-session-restore-context.js +84 -0
  75. package/dist/extensions/agent-browser/lib/managed-session-restore-policy.js +119 -0
  76. package/dist/extensions/agent-browser/lib/managed-session-restore-state.js +83 -0
  77. package/dist/extensions/agent-browser/lib/managed-session-restore.js +168 -300
  78. package/dist/extensions/agent-browser/lib/managed-session-snapshot-records.js +277 -0
  79. package/dist/extensions/agent-browser/lib/managed-session-snapshots.js +128 -305
  80. package/dist/extensions/agent-browser/lib/managed-session-storage.js +56 -253
  81. package/dist/extensions/agent-browser/lib/native-confirmation.js +140 -0
  82. package/dist/extensions/agent-browser/lib/native-output.js +43 -9
  83. package/dist/extensions/agent-browser/lib/orchestration/batch-stdin.js +106 -59
  84. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-merge.js +14 -6
  85. package/dist/extensions/agent-browser/lib/orchestration/browser-run/artifact-paths.js +109 -57
  86. package/dist/extensions/agent-browser/lib/orchestration/browser-run/browser-observation-result.js +82 -0
  87. package/dist/extensions/agent-browser/lib/orchestration/browser-run/click-dispatch.js +164 -60
  88. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostic-values.js +31 -0
  89. package/dist/extensions/agent-browser/lib/orchestration/browser-run/diagnostics.js +152 -781
  90. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-observation.js +203 -0
  91. package/dist/extensions/agent-browser/lib/orchestration/browser-run/electron-text-diagnostics.js +109 -0
  92. package/dist/extensions/agent-browser/lib/orchestration/browser-run/fill-diagnostics.js +119 -0
  93. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-action-recovery.js +147 -0
  94. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-actions.js +144 -0
  95. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-content.js +123 -0
  96. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-contracts.js +1 -0
  97. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-details.js +156 -0
  98. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-electron.js +187 -0
  99. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-evidence.js +39 -0
  100. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-missing-binary.js +89 -0
  101. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-recovery.js +97 -0
  102. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-redaction.js +106 -0
  103. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result-timeout.js +110 -0
  104. package/dist/extensions/agent-browser/lib/orchestration/browser-run/final-result.js +41 -538
  105. package/dist/extensions/agent-browser/lib/orchestration/browser-run/index.js +199 -154
  106. package/dist/extensions/agent-browser/lib/orchestration/browser-run/interaction-diagnostics.js +290 -0
  107. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-close.js +167 -0
  108. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-inspection.js +108 -0
  109. package/dist/extensions/agent-browser/lib/orchestration/browser-run/managed-session-daemon-policy.js +127 -205
  110. package/dist/extensions/agent-browser/lib/orchestration/browser-run/native-helper-observation.js +65 -0
  111. package/dist/extensions/agent-browser/lib/orchestration/browser-run/observation-types.js +1 -0
  112. package/dist/extensions/agent-browser/lib/orchestration/browser-run/overlay-diagnostics.js +120 -0
  113. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/network-page-filter.js +113 -30
  114. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/scroll-shims.js +109 -28
  115. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter-data.js +150 -0
  116. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-filter.js +147 -253
  117. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/snapshot-rendered-text.js +147 -0
  118. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare/wait-timeouts.js +59 -24
  119. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-artifacts.js +159 -0
  120. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-command.js +131 -0
  121. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-contracts.js +1 -0
  122. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-daemon.js +93 -0
  123. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-failure.js +42 -0
  124. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-guards.js +242 -0
  125. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-input.js +75 -0
  126. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-observations.js +92 -0
  127. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-selection.js +254 -0
  128. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-page-state.js +121 -0
  129. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-refs.js +130 -0
  130. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-resources.js +114 -0
  131. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-semantic.js +121 -0
  132. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-session-plan.js +222 -0
  133. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare-timeouts.js +68 -0
  134. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prepare.js +176 -1123
  135. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-analysis.js +191 -0
  136. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-confirmation.js +152 -0
  137. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-diagnostics.js +182 -0
  138. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-electron.js +150 -0
  139. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-contracts.js +1 -0
  140. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase-contracts.js +1 -0
  141. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle-phase.js +115 -0
  142. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-lifecycle.js +256 -0
  143. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed-contracts.js +1 -0
  144. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-managed.js +256 -0
  145. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase-contracts.js +1 -0
  146. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native-phase.js +93 -0
  147. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-native.js +113 -0
  148. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation-contracts.js +1 -0
  149. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-navigation.js +316 -0
  150. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-ownership.js +28 -0
  151. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase-contracts.js +1 -0
  152. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-page-phase.js +142 -0
  153. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation-contracts.js +1 -0
  154. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-presentation.js +333 -0
  155. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase-contracts.js +1 -0
  156. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication-phase.js +71 -0
  157. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-publication.js +201 -0
  158. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-receipts.js +183 -0
  159. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-refs.js +200 -0
  160. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output-tabs.js +142 -0
  161. package/dist/extensions/agent-browser/lib/orchestration/browser-run/process-output.js +18 -968
  162. package/dist/extensions/agent-browser/lib/orchestration/browser-run/prompt-guards.js +23 -13
  163. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-receipt-reconciliation.js +198 -0
  164. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-contracts.js +1 -0
  165. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery-presentation.js +154 -0
  166. package/dist/extensions/agent-browser/lib/orchestration/browser-run/recording-recovery.js +68 -151
  167. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-capture.js +14 -0
  168. package/dist/extensions/agent-browser/lib/orchestration/browser-run/screenshot-observation.js +169 -46
  169. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-commands.js +130 -0
  170. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-electron.js +212 -0
  171. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-observations.js +61 -0
  172. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-outcomes.js +187 -0
  173. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-refs.js +169 -0
  174. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state-tabs.js +228 -0
  175. package/dist/extensions/agent-browser/lib/orchestration/browser-run/session-state.js +77 -765
  176. package/dist/extensions/agent-browser/lib/orchestration/browser-run/text-visibility-diagnostics.js +182 -0
  177. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-diagnostics.js +256 -0
  178. package/dist/extensions/agent-browser/lib/orchestration/browser-run/timeout-progress.js +108 -0
  179. package/dist/extensions/agent-browser/lib/orchestration/code-artifact-observation.js +39 -0
  180. package/dist/extensions/agent-browser/lib/orchestration/code-image-observation.js +119 -0
  181. package/dist/extensions/agent-browser/lib/orchestration/electron-host/branch.js +93 -0
  182. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup-result.js +58 -0
  183. package/dist/extensions/agent-browser/lib/orchestration/electron-host/cleanup.js +78 -0
  184. package/dist/extensions/agent-browser/lib/orchestration/electron-host/contracts.js +1 -0
  185. package/dist/extensions/agent-browser/lib/orchestration/electron-host/discovery.js +106 -0
  186. package/dist/extensions/agent-browser/lib/orchestration/electron-host/index.js +48 -821
  187. package/dist/extensions/agent-browser/lib/orchestration/electron-host/policy.js +86 -0
  188. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-collection.js +68 -0
  189. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-data.js +169 -0
  190. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe-presentation.js +182 -0
  191. package/dist/extensions/agent-browser/lib/orchestration/electron-host/probe.js +161 -0
  192. package/dist/extensions/agent-browser/lib/orchestration/electron-host/status.js +167 -0
  193. package/dist/extensions/agent-browser/lib/orchestration/execution-queue.js +22 -10
  194. package/dist/extensions/agent-browser/lib/orchestration/extension-artifact-preflight.js +211 -0
  195. package/dist/extensions/agent-browser/lib/orchestration/extension-artifacts.js +23 -0
  196. package/dist/extensions/agent-browser/lib/orchestration/extension-attachment-replay.js +99 -0
  197. package/dist/extensions/agent-browser/lib/orchestration/extension-branch-restore.js +275 -0
  198. package/dist/extensions/agent-browser/lib/orchestration/extension-code.js +280 -0
  199. package/dist/extensions/agent-browser/lib/orchestration/extension-command-admission.js +303 -0
  200. package/dist/extensions/agent-browser/lib/orchestration/extension-command-output.js +36 -0
  201. package/dist/extensions/agent-browser/lib/orchestration/extension-command-result.js +335 -0
  202. package/dist/extensions/agent-browser/lib/orchestration/extension-command-run.js +227 -0
  203. package/dist/extensions/agent-browser/lib/orchestration/extension-command-state.js +1 -0
  204. package/dist/extensions/agent-browser/lib/orchestration/extension-electron-ownership.js +204 -0
  205. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-locks.js +139 -0
  206. package/dist/extensions/agent-browser/lib/orchestration/extension-execution-queue.js +24 -0
  207. package/dist/extensions/agent-browser/lib/orchestration/extension-host-coordination.js +98 -0
  208. package/dist/extensions/agent-browser/lib/orchestration/extension-host-run.js +295 -0
  209. package/dist/extensions/agent-browser/lib/orchestration/extension-intent-replay.js +41 -0
  210. package/dist/extensions/agent-browser/lib/orchestration/extension-invocation.js +7 -0
  211. package/dist/extensions/agent-browser/lib/orchestration/extension-lifecycle.js +102 -0
  212. package/dist/extensions/agent-browser/lib/orchestration/extension-managed-ownership.js +133 -0
  213. package/dist/extensions/agent-browser/lib/orchestration/extension-observation.js +120 -0
  214. package/dist/extensions/agent-browser/lib/orchestration/extension-prompt.js +180 -0
  215. package/dist/extensions/agent-browser/lib/orchestration/extension-recording.js +290 -0
  216. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-contracts.js +1 -0
  217. package/dist/extensions/agent-browser/lib/orchestration/extension-resource-replay.js +269 -0
  218. package/dist/extensions/agent-browser/lib/orchestration/extension-result-state.js +113 -0
  219. package/dist/extensions/agent-browser/lib/orchestration/extension-runtime.js +146 -0
  220. package/dist/extensions/agent-browser/lib/orchestration/extension-script-leases.js +58 -0
  221. package/dist/extensions/agent-browser/lib/orchestration/extension-tool-boundary.js +62 -0
  222. package/dist/extensions/agent-browser/lib/orchestration/extension-version-check.js +54 -0
  223. package/dist/extensions/agent-browser/lib/orchestration/input-plan-types.js +1 -0
  224. package/dist/extensions/agent-browser/lib/orchestration/input-plan.js +261 -185
  225. package/dist/extensions/agent-browser/lib/orchestration/input-redaction.js +62 -0
  226. package/dist/extensions/agent-browser/lib/orchestration/native-config.js +144 -0
  227. package/dist/extensions/agent-browser/lib/orchestration/native-root-launch.js +77 -0
  228. package/dist/extensions/agent-browser/lib/orchestration/native-session-defaults.js +210 -157
  229. package/dist/extensions/agent-browser/lib/orchestration/operation-paths.js +124 -58
  230. package/dist/extensions/agent-browser/lib/orchestration/output-file.js +197 -99
  231. package/dist/extensions/agent-browser/lib/orchestration/script-mode.js +199 -96
  232. package/dist/extensions/agent-browser/lib/owned-managed-session-context.js +55 -0
  233. package/dist/extensions/agent-browser/lib/page-target-batch.js +118 -0
  234. package/dist/extensions/agent-browser/lib/page-target-guards.js +50 -0
  235. package/dist/extensions/agent-browser/lib/page-target-navigation.js +104 -0
  236. package/dist/extensions/agent-browser/lib/page-target-validation.js +55 -246
  237. package/dist/extensions/agent-browser/lib/parsing.js +13 -4
  238. package/dist/extensions/agent-browser/lib/pi-tool-rendering.js +133 -68
  239. package/dist/extensions/agent-browser/lib/playbook.js +16 -12
  240. package/dist/extensions/agent-browser/lib/process-child.js +284 -0
  241. package/dist/extensions/agent-browser/lib/process-environment.js +13 -6
  242. package/dist/extensions/agent-browser/lib/process-errors.js +23 -0
  243. package/dist/extensions/agent-browser/lib/process-identity.js +47 -15
  244. package/dist/extensions/agent-browser/lib/process-socket-storage.js +256 -0
  245. package/dist/extensions/agent-browser/lib/process-stdout.js +74 -0
  246. package/dist/extensions/agent-browser/lib/process.js +145 -536
  247. package/dist/extensions/agent-browser/lib/prompt-artifacts.js +287 -0
  248. package/dist/extensions/agent-browser/lib/prompt-policy.js +15 -194
  249. package/dist/extensions/agent-browser/lib/read-command.js +41 -0
  250. package/dist/extensions/agent-browser/lib/read-confirmation.js +131 -68
  251. package/dist/extensions/agent-browser/lib/recording-reservations.js +118 -45
  252. package/dist/extensions/agent-browser/lib/redaction-fields.js +75 -0
  253. package/dist/extensions/agent-browser/lib/redaction-json.js +149 -0
  254. package/dist/extensions/agent-browser/lib/redaction-url.js +88 -0
  255. package/dist/extensions/agent-browser/lib/results/action-contracts.js +1 -0
  256. package/dist/extensions/agent-browser/lib/results/action-recommendations.js +28 -271
  257. package/dist/extensions/agent-browser/lib/results/artifact-contracts.js +1 -0
  258. package/dist/extensions/agent-browser/lib/results/artifact-manifest-validation.js +133 -0
  259. package/dist/extensions/agent-browser/lib/results/artifact-manifest.js +96 -94
  260. package/dist/extensions/agent-browser/lib/results/artifact-recommendations.js +73 -0
  261. package/dist/extensions/agent-browser/lib/results/categories.js +111 -54
  262. package/dist/extensions/agent-browser/lib/results/confirmation.js +29 -13
  263. package/dist/extensions/agent-browser/lib/results/editable-ref-evidence.js +62 -27
  264. package/dist/extensions/agent-browser/lib/results/electron-recommendations.js +83 -0
  265. package/dist/extensions/agent-browser/lib/results/envelope-decoding.js +48 -0
  266. package/dist/extensions/agent-browser/lib/results/envelope.js +90 -67
  267. package/dist/extensions/agent-browser/lib/results/evidence-contracts.js +1 -0
  268. package/dist/extensions/agent-browser/lib/results/failure-recommendations.js +180 -0
  269. package/dist/extensions/agent-browser/lib/results/network-routes.js +86 -45
  270. package/dist/extensions/agent-browser/lib/results/network.js +35 -12
  271. package/dist/extensions/agent-browser/lib/results/next-actions.js +49 -19
  272. package/dist/extensions/agent-browser/lib/results/presentation/artifact-files.js +320 -0
  273. package/dist/extensions/agent-browser/lib/results/presentation/artifact-format.js +138 -0
  274. package/dist/extensions/agent-browser/lib/results/presentation/artifact-images.js +113 -0
  275. package/dist/extensions/agent-browser/lib/results/presentation/artifact-verification.js +145 -0
  276. package/dist/extensions/agent-browser/lib/results/presentation/artifacts.js +99 -555
  277. package/dist/extensions/agent-browser/lib/results/presentation/batch-contracts.js +1 -0
  278. package/dist/extensions/agent-browser/lib/results/presentation/batch-recording.js +118 -0
  279. package/dist/extensions/agent-browser/lib/results/presentation/batch-redaction.js +68 -0
  280. package/dist/extensions/agent-browser/lib/results/presentation/batch-rendering.js +135 -0
  281. package/dist/extensions/agent-browser/lib/results/presentation/batch-step.js +227 -0
  282. package/dist/extensions/agent-browser/lib/results/presentation/batch-summary.js +91 -0
  283. package/dist/extensions/agent-browser/lib/results/presentation/batch.js +91 -460
  284. package/dist/extensions/agent-browser/lib/results/presentation/browser-profile-recovery.js +9 -5
  285. package/dist/extensions/agent-browser/lib/results/presentation/command-presenters.js +216 -0
  286. package/dist/extensions/agent-browser/lib/results/presentation/common.js +26 -9
  287. package/dist/extensions/agent-browser/lib/results/presentation/content.js +86 -29
  288. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-a11y.js +67 -0
  289. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-health.js +79 -0
  290. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-identity.js +199 -0
  291. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-logs.js +75 -0
  292. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network-actions.js +216 -0
  293. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-network.js +124 -0
  294. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-redaction.js +64 -0
  295. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-storage.js +209 -0
  296. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-stream.js +69 -0
  297. package/dist/extensions/agent-browser/lib/results/presentation/diagnostic-summary.js +222 -0
  298. package/dist/extensions/agent-browser/lib/results/presentation/diagnostics.js +103 -1052
  299. package/dist/extensions/agent-browser/lib/results/presentation/early-result.js +70 -0
  300. package/dist/extensions/agent-browser/lib/results/presentation/errors.js +130 -60
  301. package/dist/extensions/agent-browser/lib/results/presentation/input-contracts.js +1 -0
  302. package/dist/extensions/agent-browser/lib/results/presentation/large-output.js +60 -145
  303. package/dist/extensions/agent-browser/lib/results/presentation/navigation.js +147 -88
  304. package/dist/extensions/agent-browser/lib/results/presentation/notices.js +75 -0
  305. package/dist/extensions/agent-browser/lib/results/presentation/observation-contracts.js +1 -0
  306. package/dist/extensions/agent-browser/lib/results/presentation/observation-rendering.js +127 -0
  307. package/dist/extensions/agent-browser/lib/results/presentation/outcomes.js +120 -0
  308. package/dist/extensions/agent-browser/lib/results/presentation/output-completion.js +77 -0
  309. package/dist/extensions/agent-browser/lib/results/presentation/output-spill.js +51 -0
  310. package/dist/extensions/agent-browser/lib/results/presentation/registry.js +116 -240
  311. package/dist/extensions/agent-browser/lib/results/presentation/semantic-action.js +35 -21
  312. package/dist/extensions/agent-browser/lib/results/presentation/skills.js +109 -73
  313. package/dist/extensions/agent-browser/lib/results/presentation/source.js +109 -0
  314. package/dist/extensions/agent-browser/lib/results/presentation.js +17 -261
  315. package/dist/extensions/agent-browser/lib/results/recommendation-contracts.js +1 -0
  316. package/dist/extensions/agent-browser/lib/results/recording.js +52 -14
  317. package/dist/extensions/agent-browser/lib/results/recovery-actions.js +14 -5
  318. package/dist/extensions/agent-browser/lib/results/recovery-next-actions.js +30 -22
  319. package/dist/extensions/agent-browser/lib/results/selector-recovery-target.js +83 -0
  320. package/dist/extensions/agent-browser/lib/results/selector-recovery.js +119 -119
  321. package/dist/extensions/agent-browser/lib/results/snapshot-compact.js +266 -0
  322. package/dist/extensions/agent-browser/lib/results/snapshot-content.js +32 -0
  323. package/dist/extensions/agent-browser/lib/results/snapshot-high-value-controls.js +104 -71
  324. package/dist/extensions/agent-browser/lib/results/snapshot-refs.js +31 -11
  325. package/dist/extensions/agent-browser/lib/results/snapshot-segments.js +125 -66
  326. package/dist/extensions/agent-browser/lib/results/snapshot-spill.js +26 -7
  327. package/dist/extensions/agent-browser/lib/results/snapshot.js +28 -248
  328. package/dist/extensions/agent-browser/lib/results/text.js +16 -5
  329. package/dist/extensions/agent-browser/lib/runtime-args-validation.js +133 -0
  330. package/dist/extensions/agent-browser/lib/runtime-compatibility.js +81 -0
  331. package/dist/extensions/agent-browser/lib/runtime-contracts.js +1 -0
  332. package/dist/extensions/agent-browser/lib/runtime-redaction.js +118 -0
  333. package/dist/extensions/agent-browser/lib/runtime-replay-events.js +144 -0
  334. package/dist/extensions/agent-browser/lib/runtime-session-identity.js +76 -0
  335. package/dist/extensions/agent-browser/lib/runtime-session-plan.js +114 -0
  336. package/dist/extensions/agent-browser/lib/runtime-session-replay.js +123 -0
  337. package/dist/extensions/agent-browser/lib/runtime-tab-correction.js +65 -0
  338. package/dist/extensions/agent-browser/lib/runtime-timeouts.js +28 -0
  339. package/dist/extensions/agent-browser/lib/runtime.js +137 -1041
  340. package/dist/extensions/agent-browser/lib/session-identity.js +51 -0
  341. package/dist/extensions/agent-browser/lib/session-page-observation.js +357 -0
  342. package/dist/extensions/agent-browser/lib/session-page-state.js +178 -333
  343. package/dist/extensions/agent-browser/lib/session-page-types.js +1 -0
  344. package/dist/extensions/agent-browser/lib/temp-artifact-budget.js +81 -0
  345. package/dist/extensions/agent-browser/lib/temp-mutation-queue.js +7 -0
  346. package/dist/extensions/agent-browser/lib/temp-root-ownership.js +234 -0
  347. package/dist/extensions/agent-browser/lib/temp-root.js +211 -0
  348. package/dist/extensions/agent-browser/lib/temp.js +33 -446
  349. package/dist/extensions/agent-browser/lib/tool-surface.js +94 -24
  350. package/dist/extensions/agent-browser/lib/upstream-version.js +3 -2
  351. package/dist/extensions/agent-browser/lib/web-search-providers.js +193 -0
  352. package/dist/extensions/agent-browser/lib/web-search-request.js +102 -0
  353. package/dist/extensions/agent-browser/lib/web-search-results.js +281 -0
  354. package/dist/extensions/agent-browser/lib/web-search-schema.js +82 -0
  355. package/dist/extensions/agent-browser/lib/web-search.js +124 -614
  356. package/dist/extensions/agent-browser/lib/webmcp-observation.js +13 -6
  357. package/dist/extensions/agent-browser/lib/windows-stock-launcher.js +63 -37
  358. package/dist/extensions/agent-browser/script-worker.js +80 -43
  359. package/dist/scripts/agent-browser-target.mjs +4 -2
  360. package/docs/ARCHITECTURE.md +19 -6
  361. package/docs/CODE_QUALITY.md +267 -0
  362. package/docs/COMMAND_REFERENCE.md +272 -241
  363. package/docs/ELECTRON.md +77 -46
  364. package/docs/REFERENCE.md +869 -0
  365. package/docs/RELEASE.md +25 -22
  366. package/docs/REQUIREMENTS.md +2 -1
  367. package/docs/SUPPORT_MATRIX.md +81 -79
  368. package/docs/TOOL_CONTRACT.md +158 -125
  369. package/docs/platform-smoke.md +8 -8
  370. package/package.json +144 -120
  371. package/scripts/agent-browser-capability-baseline.mjs +361 -957
  372. package/scripts/agent-browser-target.mjs +6 -2
  373. package/scripts/build.mjs +37 -8
  374. package/scripts/capability-core-commands.mjs +193 -0
  375. package/scripts/capability-options.mjs +283 -0
  376. package/scripts/capability-samples.mjs +133 -0
  377. package/scripts/capability-section.mjs +11 -0
  378. package/scripts/config.mjs +235 -132
  379. package/scripts/convert-browser-session.mjs +30 -9
  380. package/scripts/doctor-sources.mjs +195 -0
  381. package/scripts/doctor.mjs +94 -249
  382. package/scripts/platform-smoke/artifacts.mjs +38 -11
  383. package/scripts/platform-smoke/commands.mjs +104 -0
  384. package/scripts/platform-smoke/crabbox-runner.mjs +167 -80
  385. package/scripts/platform-smoke/doctor-support.mjs +157 -0
  386. package/scripts/platform-smoke/doctor-windows.mjs +230 -0
  387. package/scripts/platform-smoke/doctor.mjs +212 -320
  388. package/scripts/platform-smoke/lease-evidence.mjs +132 -0
  389. package/scripts/platform-smoke/linux-image/Dockerfile +8 -2
  390. package/scripts/platform-smoke/suite-checks.mjs +98 -0
  391. package/scripts/platform-smoke/suite-evidence.mjs +281 -0
  392. package/scripts/platform-smoke/targets.mjs +154 -472
  393. package/scripts/platform-smoke.mjs +55 -40
  394. package/scripts/prepare.mjs +16 -7
@@ -1,1067 +1,163 @@
1
- import { createHash, randomUUID } from "node:crypto";
2
- import { basename } from "node:path";
3
- import { extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, } from "./argv-descriptor.js";
4
- import { batchHasSuccessfulCloseAll, getSuccessfulBatchCloseLifecycle } from "./batch-lifecycle.js";
5
- import { getBrowserResultMessage } from "./browser-transcript.js";
6
- import { canonicalizeAgentBrowserNamespace, extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, getBooleanFlagValue, GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES, GLOBAL_VALUE_FLAGS_ALLOWING_DASH_VALUE, isAgentBrowserSessionIdentityKeyInNamespace, isUpstreamEnvFlagEnabled, PREVALIDATED_VALUE_FLAGS, projectUpstreamGlobalFlags, resolveAgentBrowserNamespace, scanUpstreamGlobalFlagOccurrences, stripUpstreamGlobalFlags, } from "./argv-grammar.js";
1
+ import { parseArgvDescriptor } from "./argv-descriptor.js";
2
+ import { canonicalizeAgentBrowserNamespace, extractExplicitNamespace, extractExplicitSessionName, getAgentBrowserSessionIdentityKey, getBooleanFlagValue, scanUpstreamGlobalFlagOccurrences, } from "./argv-grammar.js";
7
3
  import { needsManagedSession } from "./command-policy.js";
8
- import { parseBatchCommandArgument } from "./orchestration/batch-stdin.js";
9
- import { isCloseAllCommand, isCloseCommand, isOpenNavigationCommand } from "./command-taxonomy.js";
10
- import { hasLaunchScopedFlagToken, LAUNCH_SCOPED_FLAG_DEFINITIONS, LAUNCH_SCOPED_FLAG_LABEL, } from "./launch-scoped-flags.js";
11
- import { MANAGED_SESSION_NAME_PREFIX, } from "./managed-session-restore.js";
12
- export { extractCommandTokens, extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, parseWaitCommandTokens } from "./argv-descriptor.js";
13
- import { isRecord } from "./parsing.js";
4
+ import { isCloseCommand } from "./command-taxonomy.js";
5
+ import { hasLaunchScopedFlagToken, LAUNCH_SCOPED_FLAG_DEFINITIONS } from "./launch-scoped-flags.js";
14
6
  import { getAgentBrowserProcessEnvironment } from "./process-environment.js";
15
- import { TARGET_AGENT_BROWSER_VERSION } from "./upstream-version.js";
16
- const OPENAI_HEADLESS_COMPAT_HOSTS = new Set(["chat.com", "chat.openai.com", "chatgpt.com"]);
17
- const CLOUDFLARE_HEADLESS_COMPAT_HOST = "dash.cloudflare.com";
18
- const AGENT_BROWSER_IDLE_TIMEOUT_ENV = "AGENT_BROWSER_IDLE_TIMEOUT_MS";
19
- const IMPLICIT_SESSION_IDLE_TIMEOUT_ENV = "PI_AGENT_BROWSER_IMPLICIT_SESSION_IDLE_TIMEOUT_MS";
20
- const IMPLICIT_SESSION_CLOSE_TIMEOUT_ENV = "PI_AGENT_BROWSER_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS";
21
- const DEFAULT_IMPLICIT_SESSION_IDLE_TIMEOUT_MS = 15 * 60 * 1000;
22
- // Native close includes a five-second Chrome exit grace after protocol shutdown.
23
- // Use the normal CLI watchdog budget rather than interrupting that grace.
24
- const DEFAULT_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS = 35_000;
25
- const INSPECTION_FLAGS = new Set(["--help", "-h", "--version", "-V"]);
26
- const SENSITIVE_VALUE_FLAGS = new Set(["--body", "--headers", "--password", "--proxy"]);
27
- const SENSITIVE_QUERY_PARAM_PATTERN = /^(?:access(?:_|-)?token|api(?:_|-)?key|auth|authorization|authorization(?:_|-)?session(?:_|-)?id|bearer|client(?:_|-)?secret|code|cookie|id(?:_|-)?token|key|pass(?:word)?|refresh(?:_|-)?token|relay(?:_|-)?state|saml(?:_|-)?request|saml(?:_|-)?response|secret|sentry(?:_|-)?key|session(?:_|-)?id|sig(?:nature)?|token|write(?:_|-)?key)$/i;
28
- const AUTH_STATE_QUERY_PARAM_PATTERN = /^(?:nonce|state)$/i;
29
- const AUTH_URL_CONTEXT_PATTERN = /(?:^|[./_-])(?:auth|authorize|callback|login|oauth2?|oidc|saml|sso)(?:[./?#_-]|$)/i;
30
- const SENSITIVE_FIELD_NAME_PATTERN = /^(?:[A-Za-z0-9_-]*(?:api[_-]?key|access[_-]?key|private[_-]?key|secret(?:[_-]?(?:key|access[_-]?key))?|token|password|passwd|credentials?|database[_-]?url|db[_-]?url|connection[_-]?string|mongo(?:db)?[_-]?uri|redis[_-]?url)|[A-Za-z0-9]*(?:apiKey|ApiKey|apikey|privateKey|PrivateKey|databaseUrl|DatabaseUrl|dbUrl|DbUrl|connectionString|ConnectionString|mongoUri|MongoUri|mongodbUri|MongodbUri|mongoDbUri|MongoDbUri|redisUrl|RedisUrl|Token|Secret|Password|Credential|Credentials)|auth(?:orization)?|bearer|client(?:_|-)?secret|cookie|id(?:_|-)?token|pass(?:word)?|proxy(?:_|-)?authorization|refresh(?:_|-)?token|sentry(?:_|-)?key|session(?:_|-)?id|set(?:_|-)?cookie|sig(?:nature)?|write(?:_|-)?key|x(?:_|-)?api(?:_|-)?key)$/i;
31
- const ENV_SECRET_ASSIGNMENT_PATTERN = /\b((?:export\s+)?([A-Za-z_][A-Za-z0-9_-]*)(\s*[:=]\s*))(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|[^\s,;]+)/g;
32
- const DEFAULT_HEADLESS_COMPAT_USER_AGENT_BY_PLATFORM = {
33
- darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
34
- linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
35
- win32: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
36
- };
37
- const FALLBACK_HEADLESS_COMPAT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36";
38
- const SHELL_OPERATOR_TOKENS = new Set(["&&", "||", "|", ";", ">", ">>", "<"]);
39
- const ANDROID_SESSION_NAME_IDENTITY_LENGTH = 20;
40
- const MAX_PROJECT_SLUG_LENGTH = 24;
41
- const SESSION_NAME_CWD_HASH_LENGTH = 8;
42
- const SESSION_NAME_SESSION_ID_LENGTH = 12;
43
- function isStringArray(value) {
44
- return Array.isArray(value) && value.every((item) => typeof item === "string");
45
- }
46
- function shouldRedactQueryParam(name) {
47
- return SENSITIVE_QUERY_PARAM_PATTERN.test(name) || isSensitiveFieldName(name);
48
- }
49
- function redactUrlToken(token) {
50
- let parsed;
51
- try {
52
- parsed = new URL(token);
53
- }
54
- catch {
55
- return token;
56
- }
57
- const originalHref = parsed.href;
58
- if (parsed.username.length > 0)
59
- parsed.username = "[REDACTED]";
60
- if (parsed.password.length > 0)
61
- parsed.password = "[REDACTED]";
62
- const hashText = parsed.hash.startsWith("#") ? parsed.hash.slice(1) : parsed.hash;
63
- const hashParams = hashText.includes("=") ? new URLSearchParams(hashText) : undefined;
64
- const authContext = AUTH_URL_CONTEXT_PATTERN.test(`${parsed.hostname}${parsed.pathname}`)
65
- || [...parsed.searchParams.keys(), ...(hashParams?.keys() ?? [])].some(shouldRedactQueryParam);
66
- for (const [name] of parsed.searchParams) {
67
- if (shouldRedactQueryParam(name) || (authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name))) {
68
- parsed.searchParams.set(name, "[REDACTED]");
69
- }
70
- }
71
- if (hashParams) {
72
- let hashMutated = false;
73
- for (const [name] of hashParams) {
74
- if (shouldRedactQueryParam(name) || (authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name))) {
75
- hashParams.set(name, "[REDACTED]");
76
- hashMutated = true;
77
- }
78
- }
79
- if (hashMutated)
80
- parsed.hash = `#${hashParams.toString()}`;
81
- }
82
- return parsed.href === originalHref ? token : parsed.href;
83
- }
84
- function redactLooseUrlParameterText(text) {
85
- return text.replace(/(?<![^\s"'`<>\])}])[^\s"'`<>\])}]*[?#&][^\s"'`<>\])}]*/g, (token) => {
86
- const queryNames = [...token.matchAll(/[?#&]([^=&#\s"'`<>\])}]+)=/g)].map((match) => {
87
- try {
88
- return decodeURIComponent((match[1] ?? "").replace(/\+/g, " "));
89
- }
90
- catch {
91
- return match[1] ?? "";
92
- }
93
- });
94
- const authContext = AUTH_URL_CONTEXT_PATTERN.test(token) || queryNames.some(shouldRedactQueryParam);
95
- return token.replace(/([?#&])([^=&#\s"'`<>\])}]+)=([^&#\s"'`<>\])}]*)/g, (match, separator, rawName, rawValue) => {
96
- if (rawValue === "[REDACTED" || rawValue === "[REDACTED]" || /%5Bredacted%5D/i.test(rawValue))
97
- return match;
98
- let name = rawName;
99
- try {
100
- name = decodeURIComponent(rawName.replace(/\+/g, " "));
101
- }
102
- catch {
103
- // Keep the raw name when percent decoding fails.
104
- }
105
- if (!shouldRedactQueryParam(name) && !(authContext && AUTH_STATE_QUERY_PARAM_PATTERN.test(name)))
106
- return match;
107
- return `${separator}${rawName}=[REDACTED]`;
108
- });
109
- });
110
- }
111
- function redactLooseUrlUserinfo(text) {
112
- return text.replace(/\b([A-Za-z][A-Za-z0-9+.-]*:\/\/)([^\s"'`/@]+)@([^\s"'`]+)/g, (match, prefix, userinfo, suffix) => {
113
- if (/%5Bredacted%5D/i.test(userinfo))
114
- return match;
115
- if (userinfo.includes("[REDACTED]"))
116
- return redactLooseUrlParameterText(match);
117
- return redactLooseUrlParameterText(`${prefix}${userinfo.includes(":") ? "[REDACTED]:[REDACTED]" : "[REDACTED]"}@${suffix}`);
118
- });
119
- }
120
- function redactLooseUrlMatches(text) {
121
- return text.replace(/\b[A-Za-z][A-Za-z0-9+.-]*:\/\/[^\s"'`<>\])]+/g, (match) => redactUrlToken(match));
122
- }
123
- function createBalancedJsonEndFinder(text) {
124
- let boundaries;
125
- return (startIndex) => {
126
- const opener = text[startIndex];
127
- if (opener !== "{" && opener !== "[")
128
- return undefined;
129
- if (!boundaries) {
130
- // Resolve each suffix once: skip strings and balanced groups to its first unmatched closer.
131
- boundaries = new Int32Array(text.length + 1).fill(-1);
132
- let quoteAtNext = -1;
133
- let quoteAfterNext = -1;
134
- for (let index = text.length - 1; index >= 0; index -= 1) {
135
- const char = text[index];
136
- if (char === "}" || char === "]") {
137
- boundaries[index] = index;
138
- }
139
- else if (char === '"') {
140
- boundaries[index] = quoteAtNext < 0 ? -1 : boundaries[quoteAtNext + 1];
141
- }
142
- else if (char === "{" || char === "[") {
143
- const end = boundaries[index + 1];
144
- boundaries[index] = end >= 0 && text[end] === (char === "{" ? "}" : "]") ? boundaries[end + 1] : -1;
145
- }
146
- else {
147
- boundaries[index] = boundaries[index + 1];
148
- }
149
- // Inside a string, backslash skips one character; outside, it is ordinary text.
150
- const quote = char === '"' ? index : char === "\\" ? quoteAfterNext : quoteAtNext;
151
- quoteAfterNext = quoteAtNext;
152
- quoteAtNext = quote;
153
- }
154
- }
155
- const end = boundaries[startIndex + 1];
156
- return end >= 0 && text[end] === (opener === "{" ? "}" : "]") ? end : undefined;
157
- };
158
- }
159
- function redactSerializedJson(text) {
160
- if (text === "[REDACTED]")
161
- return undefined;
162
- if (!/^\s*[\[{"\d\-tfn]/.test(text))
163
- return undefined;
164
- // Validate grammar only; rebuilding parsed values loses duplicates and numeric spelling.
165
- try {
166
- JSON.parse(text);
167
- }
168
- catch {
169
- return undefined;
170
- }
171
- let output = "";
172
- let cursor = 0;
173
- const findEnd = createBalancedJsonEndFinder(text);
174
- const strings = /"(?:\\.|[^"\\])*"/g;
175
- let match;
176
- while ((match = strings.exec(text)) !== null) {
177
- const end = strings.lastIndex;
178
- const value = JSON.parse(match[0]);
179
- const redacted = redactSensitiveText(value);
180
- if (redacted !== value) {
181
- output += text.slice(cursor, match.index) + JSON.stringify(redacted);
182
- cursor = end;
183
- }
184
- const separator = /^\s*:\s*/.exec(text.slice(end));
185
- if (!separator || !isSensitiveFieldName(value))
186
- continue;
187
- const valueStart = end + separator[0].length;
188
- let valueEnd = findEnd(valueStart);
189
- if (valueEnd !== undefined) {
190
- valueEnd += 1;
191
- }
192
- else if (text[valueStart] === '"') {
193
- strings.lastIndex = valueStart;
194
- const fieldValue = strings.exec(text);
195
- valueEnd = strings.lastIndex;
196
- if (JSON.parse(fieldValue[0]) === "[REDACTED]")
197
- continue;
198
- }
199
- else {
200
- valueEnd = valueStart;
201
- while (valueEnd < text.length && !/[\s,\]}]/.test(text[valueEnd]))
202
- valueEnd += 1;
203
- }
204
- output += text.slice(cursor, valueStart) + '"[REDACTED]"';
205
- cursor = valueEnd;
206
- strings.lastIndex = valueEnd;
207
- }
208
- return output + text.slice(cursor);
209
- }
210
- function redactEmbeddedStructuredText(text) {
211
- let output = "";
212
- let cursor = 0;
213
- const findEnd = createBalancedJsonEndFinder(text);
214
- while (cursor < text.length) {
215
- const char = text[cursor];
216
- if (char !== "{" && char !== "[") {
217
- output += char;
218
- cursor += 1;
219
- continue;
220
- }
221
- const endIndex = findEnd(cursor);
222
- if (endIndex === undefined) {
223
- output += char;
224
- cursor += 1;
225
- continue;
226
- }
227
- const candidate = text.slice(cursor, endIndex + 1);
228
- output += redactSerializedJson(candidate) ?? candidate;
229
- cursor = endIndex + 1;
230
- }
231
- return output;
232
- }
233
- function redactStandaloneBasicCredential(text) {
234
- return text.replace(/\b(Basic)\s+([A-Za-z0-9+/=]{12,})/gi, (match, label, credential) => {
235
- if (!/[0-9+/=]/.test(credential))
236
- return match;
237
- return `${label} [REDACTED]`;
238
- });
239
- }
240
- function credentialTrailingPunctuation(credential) {
241
- return credential.match(/[,.:;!?]+$/)?.[0] ?? "";
242
- }
243
- function formatRedactedCredential(label, credential, trailing = "") {
244
- return `${label} [REDACTED]${credentialTrailingPunctuation(credential)}${trailing}`;
245
- }
246
- function redactBearerCredentials(text) {
247
- return text
248
- .replace(/((?:\b([A-Za-z][A-Za-z0-9_-]*)\s*[:=]\s*|(?:^|\s)(?:-H\s*|--header(?:\s+|=)))["']?Bearer)\s+([^\s"',)\[\]]+)([),.]?)/gi, (match, label, field, credential, trailing) => {
249
- if (field && !isSensitiveFieldName(field))
250
- return match;
251
- return formatRedactedCredential(label, credential, trailing);
252
- })
253
- .replace(/\b(Bearer)\s+([^\s\\"',)\[\]]+)([),.]?)/gi, (match, label, credential, trailing) => {
254
- // Without a credential field/header, require a bearer-token shape, not prose, HTML or a URL.
255
- const token = credential.slice(0, credential.length - credentialTrailingPunctuation(credential).length);
256
- if (!/^[A-Za-z0-9._~+/-]+=*$/.test(token) || !/[0-9._~+/=-]/.test(token))
257
- return match;
258
- return formatRedactedCredential(label, credential, trailing);
259
- });
260
- }
261
- function isSensitiveFieldName(key) {
262
- SENSITIVE_FIELD_NAME_PATTERN.lastIndex = 0;
263
- return SENSITIVE_FIELD_NAME_PATTERN.test(key);
264
- }
265
- function isEnvSecretAssignmentKey(key) {
266
- if (!isSensitiveFieldName(key))
267
- return false;
268
- if (key === "password" || key.includes("_") || key.includes("-") || key === key.toUpperCase())
269
- return true;
270
- return /(?:apiKey|ApiKey|privateKey|PrivateKey|databaseUrl|DatabaseUrl|dbUrl|DbUrl|connectionString|ConnectionString|mongoUri|MongoUri|mongodbUri|MongodbUri|mongoDbUri|MongoDbUri|redisUrl|RedisUrl|Token|Secret|Password|Credential|Credentials)$/.test(key);
271
- }
272
- function redactEnvSecretAssignments(text) {
273
- return text.replace(ENV_SECRET_ASSIGNMENT_PATTERN, (match, prefix, key, _separator, offset) => {
274
- if (!isEnvSecretAssignmentKey(key))
275
- return match;
276
- if (key === "password") {
277
- // The loose matcher cannot safely distinguish inline punctuation from password characters.
278
- const end = offset + match.length;
279
- if ((offset > 0 && text[offset - 1] !== "\n" && text[offset - 1] !== "\r")
280
- || (end < text.length && text[end] !== "\n" && text[end] !== "\r")
281
- || /^(?:\[REDACTED\]|%5Bredacted%5D)/i.test(match.slice(prefix.length)))
282
- return match;
283
- const value = match.slice(prefix.length);
284
- const boundary = value[0] === '"' || value[0] === "'" ? -1 : value.search(/[&#](?=[A-Za-z_][A-Za-z0-9_-]*\s*=)/);
285
- return `${prefix}[REDACTED]${boundary < 0 ? "" : value.slice(boundary)}`;
286
- }
287
- return `${prefix}[REDACTED]`;
288
- });
289
- }
290
- export function redactSensitiveText(text) {
291
- // Redact JSON string literals before text heuristics can consume their escapes.
292
- // Non-JSON stays whole so assignments and headers retain their credential context.
293
- const serialized = redactSerializedJson(text);
294
- if (serialized !== undefined)
295
- return serialized;
296
- const embeddedRedactedText = redactEmbeddedStructuredText(text);
297
- return redactEmbeddedStructuredText(redactEnvSecretAssignments(redactStandaloneBasicCredential(redactBearerCredentials(redactLooseUrlParameterText(redactLooseUrlUserinfo(redactLooseUrlMatches(embeddedRedactedText))))
298
- .replace(/\b(Authorization\s*:\s*Basic)\s+[^\s",]+/gi, "$1 [REDACTED]")
299
- .replace(/\b(Cookie|Set-Cookie)\s*:\s*[^\n\r"]+/gi, "$1: [REDACTED]"))));
300
- }
301
- export function redactSensitiveValue(value) {
302
- if (typeof value === "string") {
303
- return redactSensitiveText(value);
304
- }
305
- if (Array.isArray(value)) {
306
- return value.map((item) => redactSensitiveValue(item));
307
- }
308
- if (!isRecord(value)) {
309
- return value;
310
- }
311
- return Object.fromEntries(Object.entries(value).map(([key, entryValue]) => {
312
- if (isSensitiveFieldName(key)) {
313
- return [key, "[REDACTED]"];
314
- }
315
- return [key, redactSensitiveValue(entryValue)];
316
- }));
317
- }
318
- function redactFlagValue(flag, value) {
319
- if (SENSITIVE_VALUE_FLAGS.has(flag)) {
320
- return "[REDACTED]";
321
- }
322
- return redactUrlToken(value);
323
- }
324
- export function redactInvocationArgs(args) {
325
- const redacted = [];
326
- let pendingValueFlag;
327
- for (const token of args) {
328
- if (pendingValueFlag) {
329
- redacted.push(redactFlagValue(pendingValueFlag, token));
330
- pendingValueFlag = undefined;
331
- continue;
332
- }
333
- const normalizedToken = token.split("=", 1)[0] ?? token;
334
- if (SENSITIVE_VALUE_FLAGS.has(normalizedToken)) {
335
- if (token.includes("=")) {
336
- redacted.push(`${normalizedToken}=[REDACTED]`);
337
- }
338
- else {
339
- redacted.push(token);
340
- pendingValueFlag = normalizedToken;
341
- }
342
- continue;
343
- }
344
- redacted.push(redactSensitiveText(redactUrlToken(token)));
345
- }
346
- const commandStartIndex = findCommandStartIndex(args);
347
- if (commandStartIndex !== undefined && args[commandStartIndex] === "set" && args[commandStartIndex + 1] === "credentials") {
348
- for (const index of [commandStartIndex + 2, commandStartIndex + 3]) {
349
- if (redacted[index] !== undefined) {
350
- redacted[index] = "[REDACTED]";
351
- }
352
- }
353
- }
354
- if (commandStartIndex !== undefined && args[commandStartIndex] === "cookies" && args[commandStartIndex + 1] === "set"
355
- && !extractUpstreamCommandTokens(args).slice(2).includes("--curl")
356
- && redacted[commandStartIndex + 3] !== undefined) {
357
- redacted[commandStartIndex + 3] = "[REDACTED]";
358
- }
359
- if (commandStartIndex !== undefined
360
- && args[commandStartIndex] === "storage"
361
- && ["local", "session"].includes(args[commandStartIndex + 1] ?? "")
362
- && args[commandStartIndex + 2] === "set"
363
- && redacted[commandStartIndex + 4] !== undefined) {
364
- redacted[commandStartIndex + 4] = "[REDACTED]";
365
- }
366
- if (commandStartIndex !== undefined && args[commandStartIndex] === "clipboard" && args[commandStartIndex + 1] === "write") {
367
- for (let index = commandStartIndex + 2; index < redacted.length; index += 1) {
368
- redacted[index] = "[REDACTED]";
369
- }
370
- }
371
- const batch = projectUpstreamGlobalFlags(args);
372
- if (batch.tokens[0] === "batch") {
373
- for (let index = 1; index < batch.tokens.length; index++) {
374
- if (batch.tokens[index] === "--bail")
375
- continue;
376
- const step = parseBatchCommandArgument(batch.tokens[index]).step;
377
- if (!step)
378
- continue;
379
- const safe = redactInvocationArgs(step);
380
- if (safe.some((token, offset) => token !== step[offset]))
381
- redacted[batch.indices[index]] = safe.map(token => `'${token.replaceAll("'", "'\\''")}'`).join(" ");
382
- }
383
- }
384
- return redacted;
385
- }
386
- export function isPlainTextInspectionArgs(args) {
387
- return args.some((token) => INSPECTION_FLAGS.has(token));
7
+ import { formatInvalidValueFlagError, getInvalidValueFlagDetails, isPlainTextInspectionArgs, } from "./runtime-args-validation.js";
8
+ import { canUseHeadlessCompatibilityUserAgent, getCompatibilityWorkaround, getDefaultHeadlessCompatUserAgent, } from "./runtime-compatibility.js";
9
+ import { freshSessionRecoveryHint, launchFlagsRecoveryReason, selectExecutionSession, stripExplicitIdentityArgs, } from "./runtime-session-plan.js";
10
+ export { extractCommandTokens, extractUpstreamCommandTokens, findCommandStartIndex, parseArgvDescriptor, parseCommandInfo, parseWaitCommandTokens, } from "./argv-descriptor.js";
11
+ export { redactSensitiveText, redactSensitiveValue, redactInvocationArgs, } from "./runtime-redaction.js";
12
+ export { getImplicitSessionIdleTimeoutMs, getImplicitSessionCloseTimeoutMs, } from "./runtime-timeouts.js";
13
+ export { isPlainTextInspectionArgs, validateToolArgs } from "./runtime-args-validation.js";
14
+ export { canUseHeadlessCompatibilityUserAgent, getDefaultHeadlessCompatUserAgent, } from "./runtime-compatibility.js";
15
+ export { createEphemeralSessionSeed, createImplicitSessionName, createFreshSessionName, isRestorableManagedSessionName, resolveManagedSessionState, } from "./runtime-session-identity.js";
16
+ export { restoreManagedSessionStateFromBranch } from "./runtime-session-replay.js";
17
+ export { chooseOpenResultTabCorrection } from "./runtime-tab-correction.js";
18
+ export function getStartupScopedFlags(args) {
19
+ return LAUNCH_SCOPED_FLAG_DEFINITIONS.map((definition) => definition.flag).filter((flag) => hasLaunchScopedFlagToken(args, flag));
388
20
  }
389
- function parseTimeoutMs(rawValue, minimumValue) {
390
- if (typeof rawValue !== "string")
391
- return undefined;
392
- const normalizedValue = rawValue.trim();
393
- if (!/^\d+$/.test(normalizedValue))
394
- return undefined;
395
- const parsedValue = Number(normalizedValue);
396
- if (!Number.isSafeInteger(parsedValue) || parsedValue < minimumValue) {
397
- return undefined;
21
+ function withNativeSession(args) {
22
+ const nativeSession = getAgentBrowserProcessEnvironment().AGENT_BROWSER_SESSION;
23
+ if (nativeSession !== undefined &&
24
+ !isPlainTextInspectionArgs(args) &&
25
+ extractExplicitSessionName(args) === undefined) {
26
+ return ["--session", nativeSession, ...args];
398
27
  }
399
- return parsedValue;
400
- }
401
- export function getImplicitSessionIdleTimeoutMs(env = getAgentBrowserProcessEnvironment()) {
402
- return parseTimeoutMs(env[IMPLICIT_SESSION_IDLE_TIMEOUT_ENV], 0) ??
403
- parseTimeoutMs(env[AGENT_BROWSER_IDLE_TIMEOUT_ENV], 0) ??
404
- DEFAULT_IMPLICIT_SESSION_IDLE_TIMEOUT_MS;
28
+ return args;
405
29
  }
406
- function countExplicitGlobalFlags(args, targetFlag) {
407
- return scanUpstreamGlobalFlagOccurrences(args, targetFlag).length;
30
+ function jsonPrefix(args) {
31
+ return getBooleanFlagValue(args, "--json") === undefined ? ["--json"] : [];
408
32
  }
409
- export function getImplicitSessionCloseTimeoutMs(env = getAgentBrowserProcessEnvironment()) {
410
- return parseTimeoutMs(env[IMPLICIT_SESSION_CLOSE_TIMEOUT_ENV], 0) ?? DEFAULT_IMPLICIT_SESSION_CLOSE_TIMEOUT_MS;
411
- }
412
- export function resolveManagedSessionState(options) {
413
- const { command, managedSessionName, priorActive, priorSessionName, succeeded } = options;
414
- const managedSessionNamespace = canonicalizeAgentBrowserNamespace(options.managedSessionNamespace);
415
- const priorNamespace = canonicalizeAgentBrowserNamespace(options.priorNamespace);
416
- if (!managedSessionName) {
417
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
418
- }
419
- if (isCloseCommand(command) && managedSessionName === priorSessionName) {
420
- if (managedSessionNamespace !== priorNamespace)
421
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
422
- const namespace = succeeded ? undefined : priorNamespace;
423
- return { active: succeeded ? false : priorActive, ...(namespace ? { namespace } : {}), sessionName: priorSessionName };
424
- }
425
- if (!succeeded) {
426
- return { active: priorActive, ...(priorNamespace ? { namespace: priorNamespace } : {}), sessionName: priorSessionName };
427
- }
428
- return {
429
- active: true,
430
- ...(managedSessionNamespace ? { namespace: managedSessionNamespace } : {}),
431
- replacedSessionName: priorActive && priorSessionName !== managedSessionName ? priorSessionName : undefined,
432
- sessionName: managedSessionName,
33
+ function planningFailure(args) {
34
+ const invalidValueFlag = getInvalidValueFlagDetails(args);
35
+ const repeatedFlag = ["--session", "--namespace"].find((flag) => scanUpstreamGlobalFlagOccurrences(args, flag).length > 1);
36
+ if (!invalidValueFlag && repeatedFlag === undefined) {
37
+ return;
38
+ }
39
+ const validationError = invalidValueFlag
40
+ ? formatInvalidValueFlagError(invalidValueFlag)
41
+ : `Multiple ${repeatedFlag ?? ""} flags are not supported. Pass a single ${repeatedFlag ?? ""} value; upstream uses the last occurrence while this wrapper would otherwise mis-attribute managed-session ownership.`;
42
+ const plan = {
43
+ commandInfo: {},
44
+ effectiveArgs: jsonPrefix(args),
45
+ plainTextInspection: false,
46
+ startupScopedFlags: [],
47
+ usedImplicitSession: false,
48
+ validationError,
433
49
  };
50
+ return invalidValueFlag ? { ...plan, invalidValueFlag } : plan;
434
51
  }
435
- export function isRestorableManagedSessionName(sessionName, fallbackSessionName) {
436
- return sessionName === fallbackSessionName || sessionName.startsWith(`${fallbackSessionName}-fresh-`);
437
- }
438
- function getManagedSessionRestoreRank(options) {
439
- const { fallbackSessionName, freshSessionRanks, sessionName } = options;
440
- if (sessionName === fallbackSessionName) {
441
- return 0;
442
- }
443
- if (!sessionName.startsWith(`${fallbackSessionName}-fresh-`)) {
444
- return undefined;
445
- }
446
- const existingRank = freshSessionRanks.get(sessionName);
447
- if (existingRank !== undefined) {
448
- return existingRank;
449
- }
450
- const nextRank = freshSessionRanks.size + 1;
451
- freshSessionRanks.set(sessionName, nextRank);
452
- return nextRank;
453
- }
454
- function getRestorableManagedSessionName(value, fallbackSessionName) {
455
- return typeof value === "string" && isRestorableManagedSessionName(value, fallbackSessionName) ? value : undefined;
456
- }
457
- function getElectronCleanupClosedManagedSessions(details, fallbackSessionName) {
458
- const electron = isRecord(details.electron) ? details.electron : undefined;
459
- const cleanup = isRecord(electron?.cleanup) ? electron.cleanup : undefined;
460
- const results = Array.isArray(cleanup?.results) ? cleanup.results : [];
461
- const closedSessions = [];
462
- for (const result of results) {
463
- if (!isRecord(result) || !Array.isArray(result.steps))
464
- continue;
465
- const record = isRecord(result.record) ? result.record : undefined;
466
- const fallbackNamespace = typeof record?.namespace === "string"
467
- ? record.namespace
468
- : typeof details.namespace === "string" ? details.namespace : undefined;
469
- for (const step of result.steps) {
470
- if (!isRecord(step) || step.resource !== "managed-session")
471
- continue;
472
- if (step.state !== "removed" && step.state !== "already-gone")
473
- continue;
474
- const sessionName = getRestorableManagedSessionName(step.sessionName, fallbackSessionName)
475
- ?? getRestorableManagedSessionName(record?.sessionName, fallbackSessionName);
476
- const namespace = typeof step.namespace === "string" ? step.namespace : fallbackNamespace;
477
- if (sessionName)
478
- closedSessions.push({ namespace, sessionName });
479
- }
480
- }
481
- return closedSessions;
482
- }
483
- export function restoreManagedSessionStateFromBranch(branch, fallbackSessionName) {
484
- const restoreDisabledIdentities = new Map();
485
- let restoredState = {
486
- active: false,
487
- sessionName: fallbackSessionName,
488
- };
489
- let activeRestoreRank = 0;
490
- let closedSessionName;
491
- let freshSessionOrdinal = 0;
492
- const freshSessionRanks = new Map();
493
- const applyManagedClose = (sessionName, namespace) => {
494
- namespace = canonicalizeAgentBrowserNamespace(namespace);
495
- const restoreRank = getManagedSessionRestoreRank({
496
- fallbackSessionName,
497
- freshSessionRanks,
498
- sessionName,
499
- });
500
- if (restoreRank === undefined || sessionName !== restoredState.sessionName || namespace !== restoredState.namespace)
501
- return;
502
- restoredState = { active: false, sessionName: restoredState.sessionName };
503
- closedSessionName = sessionName;
504
- };
505
- for (const entry of branch) {
506
- const message = getBrowserResultMessage(entry);
507
- if (!message) {
508
- continue;
509
- }
510
- const details = isRecord(message.details) ? message.details : undefined;
511
- if (!details) {
512
- continue;
513
- }
514
- const args = isStringArray(details.args) ? details.args : [];
515
- if (isPlainTextInspectionArgs(args)) {
516
- continue;
517
- }
518
- for (const cleanupSession of getElectronCleanupClosedManagedSessions(details, fallbackSessionName)) {
519
- applyManagedClose(cleanupSession.sessionName, cleanupSession.namespace);
520
- }
521
- const explicitSessionName = extractExplicitSessionName(args);
522
- const sessionName = typeof details.sessionName === "string" ? details.sessionName : undefined;
523
- const namespace = canonicalizeAgentBrowserNamespace(typeof details.namespace === "string" ? details.namespace : undefined);
524
- const sessionMode = details.sessionMode === "fresh" || details.sessionMode === "auto" ? details.sessionMode : undefined;
525
- const usedImplicitSession = details.usedImplicitSession === true;
526
- const commandTokens = extractUpstreamCommandTokens(args);
527
- const command = typeof details.command === "string" ? details.command : parseCommandInfo(args).command;
528
- const batchCloseLifecycle = getSuccessfulBatchCloseLifecycle(details.batchSteps);
529
- const nestedBatchEndsClosed = batchCloseLifecycle?.endsClosed === true;
530
- const nestedBatchRemainsActive = batchCloseLifecycle?.endsClosed === false;
531
- const closeAllApplied = details.closeAllApplied === true
532
- || (message.isError !== true && isCloseAllCommand(commandTokens))
533
- || batchHasSuccessfulCloseAll(details.batchSteps);
534
- const commandClosesSession = isCloseCommand(command) || nestedBatchEndsClosed;
535
- const outcome = typeof details.managedSessionOutcome === "object" && details.managedSessionOutcome !== null ? details.managedSessionOutcome : undefined;
536
- const outcomeStatus = typeof outcome?.status === "string" ? outcome.status : undefined;
537
- const outcomeCurrentSessionName = typeof outcome?.currentSessionName === "string" ? outcome.currentSessionName : undefined;
538
- const outcomeAttemptedSessionName = getRestorableManagedSessionName(outcome?.attemptedSessionName, fallbackSessionName);
539
- const outcomeClosedSessionName = outcomeStatus === "closed" && outcome?.succeeded === true
540
- ? outcomeAttemptedSessionName ?? getRestorableManagedSessionName(outcomeCurrentSessionName, fallbackSessionName) ?? getRestorableManagedSessionName(sessionName, fallbackSessionName)
541
- : undefined;
542
- const restorableDetailSessionName = getRestorableManagedSessionName(sessionName, fallbackSessionName);
543
- if (closeAllApplied && restoredState.active) {
544
- const restoredKey = getAgentBrowserSessionIdentityKey(restoredState.sessionName, restoredState.namespace);
545
- const resultKey = restorableDetailSessionName ? getAgentBrowserSessionIdentityKey(restorableDetailSessionName, namespace) : undefined;
546
- const retainsCurrentSession = nestedBatchRemainsActive && resultKey === restoredKey;
547
- if (isAgentBrowserSessionIdentityKeyInNamespace(restoredKey, namespace) && !retainsCurrentSession) {
548
- applyManagedClose(restoredState.sessionName, restoredState.namespace);
549
- }
550
- }
551
- const explicitCloseSessionName = commandClosesSession && explicitSessionName && restorableDetailSessionName === explicitSessionName
552
- ? restorableDetailSessionName
553
- : undefined;
554
- // Sticky restore policy is session-identity state and must apply even for explicit
555
- // `--session <current-managed>` rows that are not used for managed-session lifecycle replay.
556
- if (details.managedSessionRestoreDisabled === true && typeof sessionName === "string") {
557
- restoreDisabledIdentities.set(getAgentBrowserSessionIdentityKey(sessionName, namespace), { namespace, sessionName });
558
- }
559
- const managedSessionName = outcomeClosedSessionName ?? (!explicitSessionName &&
560
- restorableDetailSessionName &&
561
- (usedImplicitSession || sessionMode === "fresh")
562
- ? restorableDetailSessionName
563
- : commandClosesSession
564
- ? explicitCloseSessionName
565
- : undefined);
566
- if (!managedSessionName) {
567
- continue;
568
- }
569
- const restoreRank = getManagedSessionRestoreRank({
570
- fallbackSessionName,
571
- freshSessionRanks,
572
- sessionName: managedSessionName,
573
- });
574
- if (restoreRank === undefined) {
575
- continue;
576
- }
577
- freshSessionOrdinal = Math.max(freshSessionOrdinal, restoreRank);
578
- const messageIsError = typeof message.isError === "boolean" ? message.isError : undefined;
579
- const exitCode = typeof details.exitCode === "number" ? details.exitCode : undefined;
580
- const outcomeActiveAfter = outcome?.activeAfter === true;
581
- const outcomeRepresentsActiveCurrentSession = outcomeActiveAfter && outcomeCurrentSessionName === managedSessionName && (outcomeStatus === "created" || outcomeStatus === "replaced" || outcomeStatus === "unchanged");
582
- const succeeded = outcomeRepresentsActiveCurrentSession || nestedBatchRemainsActive
583
- ? true
584
- : messageIsError === undefined ? exitCode === undefined || exitCode === 0 : !messageIsError;
585
- if (commandClosesSession || outcomeClosedSessionName) {
586
- if (nestedBatchEndsClosed || outcomeClosedSessionName || succeeded) {
587
- restoreDisabledIdentities.delete(getAgentBrowserSessionIdentityKey(managedSessionName, namespace));
588
- applyManagedClose(managedSessionName, namespace);
589
- }
590
- continue;
591
- }
592
- const staleCompletion = succeeded && restoreRank < activeRestoreRank;
593
- if (staleCompletion) {
594
- continue;
595
- }
596
- restoredState = resolveManagedSessionState({
597
- command,
598
- managedSessionName,
599
- managedSessionNamespace: namespace,
600
- priorActive: restoredState.active,
601
- priorNamespace: restoredState.namespace,
602
- priorSessionName: restoredState.sessionName,
603
- succeeded,
604
- });
605
- if (succeeded && restoredState.active) {
606
- activeRestoreRank = restoreRank;
607
- closedSessionName = undefined;
608
- }
609
- }
52
+ function effectiveStartupFlags(args, managedNamespace) {
53
+ const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
54
+ const explicitNamespace = extractExplicitNamespace(args);
55
+ return getStartupScopedFlags(args).filter((flag) => !(flag === "--namespace" &&
56
+ explicitNamespacePresent &&
57
+ explicitNamespace === canonicalizeAgentBrowserNamespace(managedNamespace)));
58
+ }
59
+ function targetsActiveManagedSession(selection, options, needsSession) {
60
+ const { sessionName } = selection;
61
+ return (options.managedSessionActive &&
62
+ needsSession &&
63
+ sessionName !== undefined &&
64
+ sessionName.length > 0 &&
65
+ getAgentBrowserSessionIdentityKey(sessionName, selection.namespace) ===
66
+ getAgentBrowserSessionIdentityKey(options.managedSessionName, options.managedSessionNamespace));
67
+ }
68
+ function activeLaunchRecovery(args, flags, command, prior) {
69
+ if (flags.length === 0 ||
70
+ isCloseCommand(command) ||
71
+ (prior.validationError !== undefined && prior.validationError.length > 0)) {
72
+ return prior;
73
+ }
74
+ const explicitSession = extractExplicitSessionName(args);
75
+ const explicit = explicitSession !== undefined && explicitSession.length > 0;
76
+ const recoveryArgs = explicit ? stripExplicitIdentityArgs(args, "--session") : args;
610
77
  return {
611
- ...restoredState,
612
- ...(closedSessionName ? { closedSessionName } : {}),
613
- freshSessionOrdinal,
614
- managedSessionRestoreDisabledIdentities: [...restoreDisabledIdentities.values()],
78
+ recoveryHint: freshSessionRecoveryHint(recoveryArgs, launchFlagsRecoveryReason()),
79
+ validationError: [
80
+ `The current extension-managed agent-browser session is already running, so launch-scoped flags ${flags.join(", ")} would replace or be ignored by upstream agent-browser.`,
81
+ explicit
82
+ ? 'Remove the explicit `--session` and retry with `sessionMode: "fresh"` to force a fresh upstream launch.'
83
+ : 'Retry this call with `sessionMode: "fresh"` to force a fresh upstream launch.',
84
+ ].join(" "),
615
85
  };
616
86
  }
617
- export function createEphemeralSessionSeed() {
618
- return randomUUID();
619
- }
620
- function createCwdHash(cwd) {
621
- return createHash("sha256").update(`cwd:${cwd}`).digest("hex").slice(0, SESSION_NAME_CWD_HASH_LENGTH);
622
- }
623
- export function createImplicitSessionName(sessionId, cwd, ephemeralSeed, platform = process.platform) {
624
- const normalizedSessionId = sessionId?.replaceAll("-", "").toLowerCase();
625
- if (platform === "android") {
626
- const identity = normalizedSessionId ? `session:${normalizedSessionId}:cwd:${cwd}` : `ephemeral:${cwd}:${ephemeralSeed}`;
627
- const digest = createHash("sha256").update(identity).digest("hex").slice(0, ANDROID_SESSION_NAME_IDENTITY_LENGTH);
628
- return `${MANAGED_SESSION_NAME_PREFIX}${digest}`;
629
- }
630
- const slug = basename(cwd)
631
- .toLowerCase()
632
- .replace(/[^a-z0-9]+/g, "-")
633
- .replace(/^-+|-+$/g, "")
634
- .slice(0, MAX_PROJECT_SLUG_LENGTH) || "project";
635
- const cwdHash = createCwdHash(cwd);
636
- if (normalizedSessionId) {
637
- const stableSessionId = createHash("sha256")
638
- .update(`session:${normalizedSessionId}`)
639
- .digest("hex")
640
- .slice(0, SESSION_NAME_SESSION_ID_LENGTH);
641
- return `${MANAGED_SESSION_NAME_PREFIX}${slug}-${stableSessionId}-${cwdHash}`;
642
- }
643
- const digest = createHash("sha256")
644
- .update(`ephemeral:${cwd}:${ephemeralSeed}`)
645
- .digest("hex")
646
- .slice(0, SESSION_NAME_SESSION_ID_LENGTH);
647
- return `${MANAGED_SESSION_NAME_PREFIX}${slug}-${digest}-${cwdHash}`;
648
- }
649
- export function createFreshSessionName(baseSessionName, ephemeralSeed, ordinal) {
650
- const suffix = createHash("sha256")
651
- .update(`fresh:${baseSessionName}:${ephemeralSeed}:${ordinal}`)
652
- .digest("hex")
653
- .slice(0, 10);
654
- return `${baseSessionName}-fresh-${suffix}`;
655
- }
656
- function getSingleKeyCommandValidationError(args) {
657
- const { commandInfo, upstreamCommandTokens: commandTokens } = parseArgvDescriptor(args);
658
- const command = commandInfo.command;
659
- if (command !== "press" && command !== "key" && command !== "keydown" && command !== "keyup")
660
- return undefined;
661
- if (commandTokens.length === 2)
662
- return undefined;
663
- const label = command === "key" ? "key/press" : command;
664
- return `agent-browser ${label} accepts exactly one key argument. Do not pass a selector or ref to ${label}; focus or click the target first, then run ${command} <key> (for example: focus @e1, then press Enter).`;
665
- }
666
- function getBareMcpValidationError(args) {
667
- const { commandInfo, upstreamCommandTokens: commandTokens } = parseArgvDescriptor(args);
668
- if (commandInfo.command !== "mcp")
669
- return undefined;
670
- if (commandTokens.includes("--help") || commandTokens.includes("-h"))
671
- return undefined;
672
- return "agent-browser mcp starts a stdio MCP server for external MCP clients, not a one-shot native agent_browser tool workflow. Use the native agent_browser tool modes directly, or configure an MCP client to launch `agent-browser mcp`. Use `mcp --help` for help.";
673
- }
674
- function getUnsupportedInlineWaitDownloadError(args) {
675
- const descriptor = parseArgvDescriptor(args);
676
- if (descriptor.commandInfo.command !== "wait" || !descriptor.upstreamCommandTokens.some((token) => token.startsWith("--download=")))
677
- return undefined;
678
- return `agent-browser ${TARGET_AGENT_BROWSER_VERSION} does not support \`wait --download=<path>\`. Pass the optional path as a separate argument: \`wait --download <path>\` (or \`wait -d <path>\`).`;
679
- }
680
- function getBareNoSandboxValidationError(args, batchStep) {
681
- // Native batch rows skip global parsing; --args is effective only on the outer CLI call.
682
- const tokens = batchStep ? args : stripUpstreamGlobalFlags(args);
683
- const command = tokens[0];
684
- const leading = command === "--no-sandbox";
685
- if (!leading && (!isOpenNavigationCommand(command) || !tokens.slice(1).includes("--no-sandbox")))
686
- return undefined;
687
- const explanation = leading
688
- ? "`--no-sandbox` is not an agent-browser command."
689
- : `\`--no-sandbox\` is ignored as an option by \`${command}\`.`;
690
- return `${explanation} It is a Chromium launch argument. Put it in top-level \`--args\` and start a fresh session: { args: ["--args", "--no-sandbox", "open", "https://example.com"], sessionMode: "fresh" }. For batch, put --args before batch, not inside a step.`;
691
- }
692
- export function validateToolArgs(args, options = {}) {
693
- if (args.length === 0) {
694
- return "`args` must contain at least one agent-browser command token.";
695
- }
696
- const shellOperator = args.find((token) => SHELL_OPERATOR_TOKENS.has(token));
697
- if (shellOperator) {
698
- return `Do not pass shell operators like \`${shellOperator}\`. Pass exact agent-browser CLI arguments only.`;
699
- }
700
- const sessionModeArg = args.find((token) => token === "--session-mode" || token.startsWith("--session-mode="));
701
- if (sessionModeArg) {
702
- return "Do not pass `--session-mode` in args. Use the top-level agent_browser `sessionMode` field instead, for example { args: [\"--profile\", \"Default\", \"open\", \"https://example.com\"], sessionMode: \"fresh\" }.";
703
- }
704
- const inspection = !options.batchStep && isPlainTextInspectionArgs(args);
705
- const invalidValueFlag = inspection ? undefined : getInvalidValueFlagDetails(args, !options.batchStep);
706
- if (invalidValueFlag?.reason === "unsupported-assignment")
707
- return formatInvalidValueFlagError(invalidValueFlag, options.batchStep);
708
- return (inspection ? undefined : getBareNoSandboxValidationError(args, options.batchStep === true))
709
- ?? getBareMcpValidationError(args) ?? getSingleKeyCommandValidationError(args) ?? getUnsupportedInlineWaitDownloadError(args);
710
- }
711
- function getInvalidValueFlagDetails(args, allowRestoreAssignment = true) {
712
- for (let index = 0; index < args.length; index += 1) {
713
- const token = args[index];
714
- if (!token.startsWith("-")) {
715
- continue;
716
- }
717
- const normalizedToken = token.split("=", 1)[0] ?? token;
718
- if (token.includes("=")
719
- && (PREVALIDATED_VALUE_FLAGS.has(normalizedToken)
720
- || GLOBAL_BOOLEAN_FLAGS_WITH_OPTIONAL_VALUES.has(normalizedToken)
721
- || (!allowRestoreAssignment && normalizedToken === "--restore"))) {
722
- return {
723
- flag: normalizedToken,
724
- index,
725
- reason: "unsupported-assignment",
726
- };
727
- }
728
- if (!PREVALIDATED_VALUE_FLAGS.has(normalizedToken)) {
729
- continue;
730
- }
731
- const receivedToken = args[index + 1];
732
- if (receivedToken === undefined || (normalizedToken === "--args" && receivedToken.length === 0)) {
733
- return {
734
- flag: normalizedToken,
735
- index,
736
- reason: "missing-value",
737
- };
738
- }
739
- if (receivedToken.startsWith("-") && !GLOBAL_VALUE_FLAGS_ALLOWING_DASH_VALUE.has(normalizedToken)) {
740
- return {
741
- flag: normalizedToken,
742
- index,
743
- reason: "unexpected-flag",
744
- receivedToken,
745
- };
746
- }
747
- index += 1;
748
- }
749
- return undefined;
750
- }
751
- function formatInvalidValueFlagError(details, batchStep = false) {
752
- if (details.reason === "unsupported-assignment") {
753
- if (batchStep) {
754
- return details.flag === "--restore"
755
- ? "Global `--restore=<key>` belongs before `batch` in top-level args, not inside a batch step."
756
- : `Global \`${details.flag}=<value>\` is not supported inside a batch step. Move \`${details.flag}\` and its value before \`batch\` as separate top-level args.`;
757
- }
758
- return `agent-browser ${TARGET_AGENT_BROWSER_VERSION} does not support \`${details.flag}=<value>\`. Pass \`${details.flag}\` and its value as separate arguments.`;
759
- }
760
- if (details.reason === "unexpected-flag" && details.receivedToken) {
761
- return `Flag \`${details.flag}\` requires a value, but received \`${details.receivedToken}\` instead. Pass a non-flag value immediately after \`${details.flag}\`.`;
762
- }
763
- return `Flag \`${details.flag}\` requires a value immediately after it. Pass a non-flag token like \`${details.flag} demo\`.`;
764
- }
765
- function hasFlagToken(args, flag) {
766
- return args.some((token) => token === flag || token.startsWith(`${flag}=`));
767
- }
768
- function normalizeComparableUrl(url) {
769
- const normalizedUrl = url.trim();
770
- if (normalizedUrl.length === 0) {
771
- return undefined;
87
+ function activeCompatibilityPlan(args, requested, existing, prior) {
88
+ if (!canUseHeadlessCompatibilityUserAgent(args)) {
89
+ return { ...prior, compatibilityWorkaround: requested };
772
90
  }
773
- try {
774
- const parsedUrl = new URL(normalizedUrl);
775
- parsedUrl.hash = "";
776
- return parsedUrl.toString();
777
- }
778
- catch {
779
- return undefined;
780
- }
781
- }
782
- function normalizeTabSelectionValue(value) {
783
- const normalizedValue = value?.trim();
784
- return normalizedValue && normalizedValue.length > 0 ? normalizedValue : undefined;
785
- }
786
- function extractTabSelection(tab) {
787
- const tabId = normalizeTabSelectionValue(tab.tabId);
788
- if (tabId) {
789
- return { selectedTab: tabId, selectionKind: "tabId" };
790
- }
791
- const label = normalizeTabSelectionValue(tab.label);
792
- if (label) {
793
- return { selectedTab: label, selectionKind: "label" };
794
- }
795
- if (typeof tab.index === "number" && Number.isInteger(tab.index) && tab.index >= 0) {
796
- return { selectedTab: String(tab.index), selectionKind: "index" };
797
- }
798
- return undefined;
799
- }
800
- function parseComparableNavigationUrl(url) {
801
- try {
802
- return new URL(url);
803
- }
804
- catch {
805
- try {
806
- return new URL(`https://${url}`);
807
- }
808
- catch {
809
- return undefined;
810
- }
811
- }
812
- }
813
- export function getDefaultHeadlessCompatUserAgent(platform = process.platform) {
814
- return DEFAULT_HEADLESS_COMPAT_USER_AGENT_BY_PLATFORM[platform] ?? FALLBACK_HEADLESS_COMPAT_USER_AGENT;
815
- }
816
- export function canUseHeadlessCompatibilityUserAgent(args, env = getAgentBrowserProcessEnvironment()) {
817
- if (env.AGENT_BROWSER_SESSION !== undefined)
818
- return false;
819
- if (hasFlagToken(args, "--user-agent") || hasFlagToken(args, "--args"))
820
- return false;
821
- if (hasFlagToken(args, "--cdp") || hasFlagToken(args, "--provider") || hasFlagToken(args, "-p"))
822
- return false;
823
- if (env.AGENT_BROWSER_USER_AGENT !== undefined || env.AGENT_BROWSER_ARGS !== undefined || env.AGENT_BROWSER_CDP !== undefined || env.AGENT_BROWSER_PROVIDER !== undefined)
824
- return false;
825
- if ((getBooleanFlagValue(args, "--headed") ?? isUpstreamEnvFlagEnabled(env.AGENT_BROWSER_HEADED))
826
- || (getBooleanFlagValue(args, "--auto-connect") ?? isUpstreamEnvFlagEnabled(env.AGENT_BROWSER_AUTO_CONNECT)))
827
- return false;
828
- const engine = scanUpstreamGlobalFlagOccurrences(args, "--engine").at(-1)?.value ?? env.AGENT_BROWSER_ENGINE;
829
- return !engine || engine === "chrome";
830
- }
831
- function getCompatibilityWorkaround(args, commandInfo) {
832
- if (!commandInfo.command || !isOpenNavigationCommand(commandInfo.command) || !commandInfo.subcommand || !canUseHeadlessCompatibilityUserAgent(args))
833
- return undefined;
834
- const parsedTargetUrl = parseComparableNavigationUrl(commandInfo.subcommand);
835
- if (!parsedTargetUrl || !["http:", "https:"].includes(parsedTargetUrl.protocol))
836
- return undefined;
837
- const hostname = parsedTargetUrl.hostname.toLowerCase();
838
- if (hostname === CLOUDFLARE_HEADLESS_COMPAT_HOST) {
91
+ if (requested &&
92
+ !existing &&
93
+ (prior.validationError === undefined || prior.validationError.length === 0)) {
94
+ const sessionName = extractExplicitSessionName(args);
95
+ const explicit = sessionName !== undefined && sessionName.length > 0;
96
+ const recoveryArgs = explicit ? stripExplicitIdentityArgs(args, "--session") : args;
839
97
  return {
840
- id: "cloudflare-headless-user-agent",
841
- reason: "Cloudflare Dashboard challenges the default headless Chrome user agent; inject a normal Chrome user agent so authenticated headless browsing reaches the dashboard instead of Turnstile.",
98
+ compatibilityWorkaround: undefined,
99
+ recoveryHint: freshSessionRecoveryHint(recoveryArgs, "The requested site compatibility user agent is launch-scoped and needs a fresh browser session."),
100
+ validationError: explicit
101
+ ? 'The current extension-managed agent-browser session is already running without the user agent required by this site. Remove the explicit `--session` and retry with `sessionMode: "fresh"` so the compatibility user agent is applied at launch.'
102
+ : 'The current extension-managed agent-browser session is already running without the user agent required by this site. Retry this call with `sessionMode: "fresh"` so the compatibility user agent is applied at launch.',
842
103
  };
843
104
  }
844
- if (!OPENAI_HEADLESS_COMPAT_HOSTS.has(hostname))
845
- return undefined;
105
+ return { ...prior, compatibilityWorkaround: requested ?? existing };
106
+ }
107
+ function inspectionPlan(args, commandInfo, startupScopedFlags) {
108
+ const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
846
109
  return {
847
- id: "chatgpt-headless-user-agent",
848
- reason: "OpenAI web properties currently challenge the default headless Chrome user agent; inject a normal Chrome user agent to preserve the default headless workflow without requiring headed mode or auto-connect.",
110
+ commandInfo,
111
+ effectiveArgs: [...args],
112
+ namespace: explicitNamespacePresent ? (extractExplicitNamespace(args) ?? "") : undefined,
113
+ plainTextInspection: true,
114
+ startupScopedFlags,
115
+ usedImplicitSession: false,
849
116
  };
850
117
  }
851
- function stripExplicitSessionArgs(args) {
852
- const sessionTokenIndexes = new Set();
853
- for (const occurrence of scanUpstreamGlobalFlagOccurrences(args, "--session")) {
854
- sessionTokenIndexes.add(occurrence.index);
855
- sessionTokenIndexes.add(occurrence.index + 1);
856
- }
857
- return args.filter((_token, index) => !sessionTokenIndexes.has(index));
858
- }
859
- function stripExplicitNamespaceArgs(args) {
860
- const namespaceTokenIndexes = new Set();
861
- for (const occurrence of scanUpstreamGlobalFlagOccurrences(args, "--namespace")) {
862
- namespaceTokenIndexes.add(occurrence.index);
863
- namespaceTokenIndexes.add(occurrence.index + 1);
864
- }
865
- return args.filter((_token, index) => !namespaceTokenIndexes.has(index));
866
- }
867
- export function getStartupScopedFlags(args) {
868
- return LAUNCH_SCOPED_FLAG_DEFINITIONS
869
- .map((definition) => definition.flag)
870
- .filter((flag) => hasLaunchScopedFlagToken(args, flag));
871
- }
872
- export function buildExecutionPlan(args, options) {
873
- const nativeSession = getAgentBrowserProcessEnvironment().AGENT_BROWSER_SESSION;
874
- if (nativeSession !== undefined && !isPlainTextInspectionArgs(args) && extractExplicitSessionName(args) === undefined)
875
- args = ["--session", nativeSession, ...args];
876
- const invalidValueFlag = getInvalidValueFlagDetails(args);
877
- const explicitNamespacePresent = scanUpstreamGlobalFlagOccurrences(args, "--namespace").length > 0;
878
- const explicitNamespace = extractExplicitNamespace(args);
879
- const managedSessionNamespace = canonicalizeAgentBrowserNamespace(options.managedSessionNamespace);
880
- const startupScopedFlags = getStartupScopedFlags(args).filter((flag) => !(flag === "--namespace" && explicitNamespacePresent && explicitNamespace === managedSessionNamespace));
881
- const plainTextInspection = isPlainTextInspectionArgs(args);
882
- const argvDescriptor = parseArgvDescriptor(args);
883
- const commandInfo = argvDescriptor.commandInfo;
884
- const commandNeedsManagedSession = !plainTextInspection && !options.browserIndependentReadConfirmation && needsManagedSession(argvDescriptor, options.stdin);
885
- const effectiveArgs = plainTextInspection ? [...args] : getBooleanFlagValue(args, "--json") !== undefined ? [] : ["--json"];
886
- let namespace = explicitNamespacePresent ? explicitNamespace ?? "" : undefined;
887
- if (plainTextInspection) {
888
- return {
889
- commandInfo,
890
- effectiveArgs,
891
- namespace,
892
- plainTextInspection,
893
- startupScopedFlags,
894
- usedImplicitSession: false,
895
- };
896
- }
897
- if (invalidValueFlag) {
898
- return {
899
- commandInfo: {},
900
- effectiveArgs,
901
- invalidValueFlag,
902
- plainTextInspection: false,
903
- startupScopedFlags: [],
904
- usedImplicitSession: false,
905
- validationError: formatInvalidValueFlagError(invalidValueFlag),
906
- };
907
- }
908
- for (const flag of ["--session", "--namespace"]) {
909
- if (countExplicitGlobalFlags(args, flag) <= 1)
910
- continue;
911
- return {
912
- commandInfo: {},
913
- effectiveArgs,
914
- plainTextInspection: false,
915
- startupScopedFlags: [],
916
- usedImplicitSession: false,
917
- validationError: `Multiple ${flag} flags are not supported. Pass a single ${flag} value; upstream uses the last occurrence while this wrapper would otherwise mis-attribute managed-session ownership.`,
918
- };
919
- }
920
- const explicitSessionName = extractExplicitSessionName(args);
921
- if (explicitSessionName && !explicitNamespacePresent) {
922
- const targetsCurrentManagedSession = options.managedSessionActive
923
- && getAgentBrowserSessionIdentityKey(explicitSessionName, managedSessionNamespace)
924
- === getAgentBrowserSessionIdentityKey(options.managedSessionName, managedSessionNamespace);
925
- namespace = targetsCurrentManagedSession
926
- ? managedSessionNamespace
927
- : resolveAgentBrowserNamespace(args, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE);
928
- }
929
- const shouldCreateFreshManagedSession = !explicitSessionName && options.sessionMode === "fresh" && commandInfo.command !== undefined && !isCloseCommand(commandInfo.command);
930
- let argsToAppend = args;
931
- const requestedCompatibilityWorkaround = getCompatibilityWorkaround(args, commandInfo);
932
- let compatibilityWorkaround = requestedCompatibilityWorkaround;
933
- if (explicitSessionName && explicitNamespacePresent) {
934
- effectiveArgs.push("--namespace", explicitNamespace ?? "");
935
- argsToAppend = stripExplicitNamespaceArgs(args);
936
- }
937
- let managedSessionName;
938
- let recoveryHint;
939
- let sessionName = explicitSessionName;
940
- let usedImplicitSession = false;
941
- let validationError;
942
- if (!explicitSessionName && options.sessionMode === "auto" && commandNeedsManagedSession) {
943
- if (options.managedSessionActive && startupScopedFlags.length > 0) {
944
- recoveryHint = {
945
- exampleArgs: args,
946
- exampleParams: { args, sessionMode: "fresh" },
947
- reason: `Launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}) need a fresh upstream launch once the extension-managed session is already active.`,
948
- recommendedSessionMode: "fresh",
949
- };
950
- validationError = [
951
- `The current extension-managed agent-browser session is already running, so launch-scoped flags ${startupScopedFlags.join(", ")} would be ignored by upstream agent-browser.`,
952
- "Retry this call with `sessionMode: \"fresh\"` to force a fresh upstream launch, or pass an explicit `--session ...` if you want to name the new session yourself.",
953
- ].join(" ");
954
- }
955
- else {
956
- namespace = explicitNamespacePresent ? explicitNamespace ?? "" : managedSessionNamespace;
957
- if (namespace !== undefined)
958
- effectiveArgs.push("--namespace", namespace);
959
- effectiveArgs.push("--session", options.managedSessionName);
960
- if (explicitNamespacePresent)
961
- argsToAppend = stripExplicitNamespaceArgs(args);
962
- managedSessionName = options.managedSessionName;
963
- sessionName = options.managedSessionName;
964
- usedImplicitSession = true;
965
- }
966
- }
967
- else if (shouldCreateFreshManagedSession && commandNeedsManagedSession) {
968
- if (namespace !== undefined)
969
- effectiveArgs.push("--namespace", namespace);
970
- effectiveArgs.push("--session", options.freshSessionName);
971
- if (explicitNamespacePresent)
972
- argsToAppend = stripExplicitNamespaceArgs(args);
973
- managedSessionName = options.freshSessionName;
974
- sessionName = options.freshSessionName;
975
- }
976
- if (commandInfo.command !== undefined && !sessionName && !explicitNamespacePresent) {
977
- namespace = resolveAgentBrowserNamespace(args, getAgentBrowserProcessEnvironment().AGENT_BROWSER_NAMESPACE);
978
- }
979
- const targetsActiveManagedSession = options.managedSessionActive
980
- && commandNeedsManagedSession
981
- && sessionName
982
- && getAgentBrowserSessionIdentityKey(sessionName, namespace) === getAgentBrowserSessionIdentityKey(options.managedSessionName, options.managedSessionNamespace);
983
- if (targetsActiveManagedSession && startupScopedFlags.length > 0 && !isCloseCommand(commandInfo.command) && !validationError) {
984
- const recoveryArgs = explicitSessionName ? stripExplicitSessionArgs(args) : args;
985
- recoveryHint = {
986
- exampleArgs: recoveryArgs,
987
- exampleParams: { args: recoveryArgs, sessionMode: "fresh" },
988
- reason: `Launch-scoped flags (${LAUNCH_SCOPED_FLAG_LABEL}) need a fresh upstream launch once the extension-managed session is already active.`,
989
- recommendedSessionMode: "fresh",
990
- };
991
- validationError = [
992
- `The current extension-managed agent-browser session is already running, so launch-scoped flags ${startupScopedFlags.join(", ")} would replace or be ignored by upstream agent-browser.`,
993
- explicitSessionName
994
- ? "Remove the explicit `--session` and retry with `sessionMode: \"fresh\"` to force a fresh upstream launch."
995
- : "Retry this call with `sessionMode: \"fresh\"` to force a fresh upstream launch.",
996
- ].join(" ");
997
- }
998
- if (targetsActiveManagedSession && canUseHeadlessCompatibilityUserAgent(args)) {
999
- if (requestedCompatibilityWorkaround && !options.managedSessionCompatibilityWorkaround && !validationError) {
1000
- compatibilityWorkaround = undefined;
1001
- const recoveryArgs = explicitSessionName ? stripExplicitSessionArgs(args) : args;
1002
- recoveryHint = {
1003
- exampleArgs: recoveryArgs,
1004
- exampleParams: { args: recoveryArgs, sessionMode: "fresh" },
1005
- reason: "The requested site compatibility user agent is launch-scoped and needs a fresh browser session.",
1006
- recommendedSessionMode: "fresh",
1007
- };
1008
- validationError = explicitSessionName
1009
- ? "The current extension-managed agent-browser session is already running without the user agent required by this site. Remove the explicit `--session` and retry with `sessionMode: \"fresh\"` so the compatibility user agent is applied at launch."
1010
- : "The current extension-managed agent-browser session is already running without the user agent required by this site. Retry this call with `sessionMode: \"fresh\"` so the compatibility user agent is applied at launch.";
1011
- }
1012
- else {
1013
- compatibilityWorkaround = requestedCompatibilityWorkaround ?? options.managedSessionCompatibilityWorkaround;
1014
- }
1015
- }
1016
- if (compatibilityWorkaround && !targetsActiveManagedSession) {
118
+ export function buildExecutionPlan(inputArgs, options) {
119
+ const args = withNativeSession(inputArgs);
120
+ const startupScopedFlags = effectiveStartupFlags(args, options.managedSessionNamespace);
121
+ const descriptor = parseArgvDescriptor(args);
122
+ const commandInfo = descriptor.commandInfo;
123
+ if (isPlainTextInspectionArgs(args)) {
124
+ return inspectionPlan(args, commandInfo, startupScopedFlags);
125
+ }
126
+ const failure = planningFailure(args);
127
+ if (failure) {
128
+ return failure;
129
+ }
130
+ const needsSession = options.browserIndependentReadConfirmation !== true &&
131
+ needsManagedSession(descriptor, options.stdin);
132
+ const selection = selectExecutionSession(args, options, {
133
+ command: commandInfo.command,
134
+ needsManagedSession: needsSession,
135
+ startupScopedFlags,
136
+ });
137
+ const activeTarget = targetsActiveManagedSession(selection, options, needsSession);
138
+ const requested = getCompatibilityWorkaround(args, commandInfo);
139
+ const recovery = activeTarget
140
+ ? activeLaunchRecovery(args, startupScopedFlags, commandInfo.command, selection)
141
+ : selection;
142
+ const compatibility = activeTarget
143
+ ? activeCompatibilityPlan(args, requested, options.managedSessionCompatibilityWorkaround, recovery)
144
+ : { ...recovery, compatibilityWorkaround: requested };
145
+ const effectiveArgs = [...jsonPrefix(args), ...selection.prefixArgs];
146
+ if (compatibility.compatibilityWorkaround && !activeTarget) {
1017
147
  effectiveArgs.push("--user-agent", getDefaultHeadlessCompatUserAgent());
1018
148
  }
1019
- effectiveArgs.push(...argsToAppend);
149
+ effectiveArgs.push(...selection.argsToAppend);
1020
150
  return {
1021
151
  commandInfo,
1022
- compatibilityWorkaround,
152
+ compatibilityWorkaround: compatibility.compatibilityWorkaround,
1023
153
  effectiveArgs,
1024
- managedSessionName,
1025
- namespace,
1026
- plainTextInspection,
1027
- recoveryHint,
1028
- sessionName,
154
+ managedSessionName: selection.managedSessionName,
155
+ namespace: selection.namespace,
156
+ plainTextInspection: false,
157
+ recoveryHint: compatibility.recoveryHint,
158
+ sessionName: selection.sessionName,
1029
159
  startupScopedFlags,
1030
- usedImplicitSession,
1031
- validationError,
160
+ usedImplicitSession: selection.usedImplicitSession,
161
+ validationError: compatibility.validationError,
1032
162
  };
1033
163
  }
1034
- export function chooseOpenResultTabCorrection(options) {
1035
- const normalizedTargetUrl = typeof options.targetUrl === "string" ? normalizeComparableUrl(options.targetUrl) : undefined;
1036
- if (!normalizedTargetUrl) {
1037
- return undefined;
1038
- }
1039
- const tabsWithIndices = options.tabs.map((tab, index) => ({
1040
- ...tab,
1041
- index: typeof tab.index === "number" ? tab.index : index,
1042
- label: normalizeTabSelectionValue(tab.label),
1043
- tabId: normalizeTabSelectionValue(tab.tabId),
1044
- }));
1045
- const activeTab = tabsWithIndices.find((tab) => tab.active === true) ??
1046
- (typeof options.activeTabIndex === "number" ? tabsWithIndices.find((tab) => tab.index === options.activeTabIndex) : undefined);
1047
- if (activeTab && normalizeComparableUrl(activeTab.url ?? "") === normalizedTargetUrl) {
1048
- return undefined;
1049
- }
1050
- const matchingTabs = tabsWithIndices.filter((tab) => normalizeComparableUrl(tab.url ?? "") === normalizedTargetUrl);
1051
- if (matchingTabs.length === 0) {
1052
- return undefined;
1053
- }
1054
- const trimmedTargetTitle = typeof options.targetTitle === "string" ? options.targetTitle.trim() : "";
1055
- const titledMatch = trimmedTargetTitle.length === 0
1056
- ? undefined
1057
- : matchingTabs.find((tab) => typeof tab.title === "string" && tab.title.trim() === trimmedTargetTitle);
1058
- const selectedTab = titledMatch ?? matchingTabs[0];
1059
- const tabSelection = extractTabSelection(selectedTab);
1060
- return tabSelection
1061
- ? {
1062
- ...tabSelection,
1063
- targetTitle: trimmedTargetTitle.length > 0 ? trimmedTargetTitle : undefined,
1064
- targetUrl: normalizedTargetUrl,
1065
- }
1066
- : undefined;
1067
- }